Py_DECREF和PY_INCREF的目的是什么?
我在看关于如何在Python中定义“新类型”的教程,https://docs.python.org/2/extending/newtypes.html,但是我不太明白在这段代码中使用Py_DECREF的目的是什么。
static PyObject *
Noddy_new(PyTypeObject *type, PyObject *args, PyObject *kwds)
{
Noddy *self;
self = (Noddy *)type->tp_alloc(type, 0);
if (self != NULL) {
self->first = PyString_FromString("");
if (self->first == NULL)
{
Py_DECREF(self);
return NULL;
}
self->last = PyString_FromString("");
if (self->last == NULL)
{
Py_DECREF(self);
return NULL;
}
self->number = 0;
}
return (PyObject *)self;
}
我对引用计数的理解还不太清楚,任何帮助都非常感谢。
3 个回答
引用计数是一种管理内存的方法,Python会记录有多少个“拥有引用”指向一个对象。当你创建一个新的“拥有引用”指向某个对象时,引用计数就需要加1;当一个拥有引用不再使用这个对象时,引用计数就需要减1。如果引用计数降到0,说明没有人再使用这个对象了,这时就可以释放它的内存。
C语言没有自动处理引用计数的功能,所以需要手动来管理。为了减少增加和减少引用计数的操作,Python的C API引入了“借用”和“窃取”引用的概念。一般来说,参数是借用引用,而返回值则是转移引用的所有权。不过也有一些例外,比如处理列表和元组的函数。
tp_alloc函数会创建一个新的对象,并给它一个引用,然后把这个引用的所有权转给你。在正常情况下,你会在完成对象的构建后,把这个引用的所有权再转给调用你函数的地方。
但如果出现问题,你可能会有一个构建不完全的对象需要处理,这时候就需要调用Py_Decref来减少引用计数。
在这个情况下,Py_DECREF 只是释放了用 tp->alloc 分配的内存。
tp->alloc 会把引用计数设置为 1。Py_DECREF 会把引用计数从 1 减少到 0;当它发现引用计数变为 0 时,就会调用相应的函数来释放内存(在这个例子中是 Noddy_dealloc)。
如果一个 Python C API 函数返回 NULL,那就说明出现了问题;通常会设置一个异常(保存在一个全局变量中)。
如果调用者再次返回 NULL,异常就会被链接在一起,所以才会出现 'return NULL' 的情况。
CPython的垃圾回收器使用了一种叫做“引用计数”的方法,也就是说,它会维护一个对象的引用列表。如果一个对象的引用计数降到零,就意味着这个对象可以被安全地释放掉,不再占用内存空间。
因此,当我们定义PyObjects时,必须明确地调用Py_INCREF和Py_DECREF,这两个函数分别用来增加和减少对象的引用计数。