为什么在C中返回Py_None之前需要执行Py_INCREF(Py_None)?
Py_INCREF(Py_None);
return Py_None;
如果省略 Py_INCREF(Py_None),会发生什么?为什么在C中返回Py_None之前需要执行Py_INCREF(Py_None)?
Py_INCREF(Py_None);
return Py_None;
如果省略 Py_INCREF(Py_None),会发生什么?Py_INCREF
会导致对 Py_None
的引用计数不正确,这可能会导致解释器释放 Py_None
。由于 Py_None
在 Objects/object.c
文件中静态分配:PyObject _Py_NoneStruct = {
_PyObject_EXTRA_INIT
1, &PyNone_Type
};
而在Include/object.h
中有以下定义:
#define Py_None (&_Py_NoneStruct)
那么会发生的情况是,解释器将崩溃并显示致命错误:
Fatal Python error: deallocating None
Objects/object.c
中的none_dealloc
函数生成:/* ARGUSED */
static void
none_dealloc(PyObject* ignore)
{
/* This should never get called, but we also don't want to SEGV if
* we accidentally decref None out of existence.
*/
Py_FatalError("deallocating None");
}
NoneType
没有自己的释放函数,那么在堆栈上进行free
调用时会导致段错误。您可以复制tutorial中的示例,将Py_DECREF(Py_None)
调用添加到Noddy_name
函数中,构建扩展并循环调用该方法来测试此问题。
0
可能会导致程序以多种不同的方式失败。>>> None #or whatever object that was deallocated
<ARandomObjectYouNeverSawBefore object at ...>
(这其实 曾经 在我编写C扩展时发生过。由于缺少对Py_INCREF
的调用,一些对象会在随机时间变成只读缓冲区)。
在其他情况下,可能会引发不同类型的错误,或者解释器可能会崩溃或段错误。
Py_None
实际上只是另一个Python对象,但没有方法。
Python将计算对任何PyObject*
的引用。无论是字符串、整数还是None都一样。
如果您不增加引用计数,则Python解释器最终会在其引用计数达到0后丢弃该对象,认为没有指向该对象的指针。这意味着下次尝试使用返回值时,您将跟随指向内存中不保证保存Py_None
的位置的指针(错误、奇怪的值、分段故障等)。
有替代方法可以避免记住使用Py_INCREF(Py_None)
:
return Py_BuildValue("");
或者Py_RETURN_NONE;
Py_DECREF
将尝试释放它)。在64位Python上,需要更多的未处理DECREF
才能遇到问题,但从技术上讲,这是可能的。 - ShadowRanger
PyNone
可能是静态分配的(我没有Python源代码可以查找),因此我们会尝试释放静态分配的内存,这将非常有趣...无论如何,这样做没有任何好处。 - Vooobject.c
中),这导致了致命错误。无论如何,我的推理是正确的,只是适用于忘记增加通用对象引用计数的更一般情况。 - Bakuriu