Python CApi参考计数详细信息

我在这里查看一些示例代码(https://docs.python.org/2.0/api/refcountDetails.html),并试图更好地理解两个示例之间的区别:第一个示例是:


PyObject *t;


t = PyTuple_New(3);

PyTuple_SetItem(t, 0, PyInt_FromLong(1L));

PyTuple_SetItem(t, 1, PyInt_FromLong(2L));

PyTuple_SetItem(t, 2, PyString_FromString("three"));

作者解释说PyTuple_SetItem()会窃取该引用(因此无需对其进行DECREF)。 很好,我明白了。然后,作者使用PySequence_SetItem()呈现了类似的代码,该代码不会窃取引用,因此调用者必须使用DECREF,示例代码如下所示:


PyObject *l, *x;


l = PyList_New(3);

x = PyInt_FromLong(1L);

PySequence_SetItem(l, 0, x); Py_DECREF(x);

x = PyInt_FromLong(2L);

PySequence_SetItem(l, 1, x); Py_DECREF(x);

x = PyString_FromString("three");

PySequence_SetItem(l, 2, x); Py_DECREF(x);

PyObject *l, *x;

我的问题是,如果第二个示例与传递PyTYPE_FromSOMETYPE的第一个示例类似,将会发生什么情况?


PyObject *l;


l = PyList_New(3);

PySequence_SetItem(l, 0, PyInt_FromLong(1L));

PySequence_SetItem(l, 1, PyInt_FromLong(2L));

PySequence_SetItem(l, 2, PyString_FromString("three"));

最后一种情况是良性的,还是会导致内存泄漏(因为PySequence_SetItem不会获得PyInt_FromLong和PyString_FromString创建的引用的所有权,并且调用方也不会对其进行DECREF)?


慕容3067478
浏览 183回答 1
1回答

慕的地6264312

这会导致内存泄漏。创建对象时,它的引用计数为1。对象只有在引用计数变为0时才会被删除。第一个示例:将新对象传递给窃取引用(获得所有权)的函数(如)时,PyTuple_SetItemrefcount不会增加,因此仍为1。当元组最终被销毁并对其所有元素进行refref时,计数将降为0,因此将其销毁。一切都很好。第三个示例:将新对象传递给不会窃取引用(创建新引用)的函数(如)时,PySequence_SetItemrefcount会增加,因此为2。当元组最终被销毁并对其所有元素进行refref时, count将下降到1,因此不会被销毁。而且,由于没有其他人可以引用它了(除非您将其存储在某个地方),所以任何人都无法对它进行解引用。所以它泄漏了。第二个示例:将新对象传递给不会窃取引用(创建新引用)的函数(如),PySequence_SetItem然后调用Py_DECREF它时,refcount递增为2,然后递减为1。最终被销毁并对其所有元素进行refref,计数将降至0。一切都变好了。如果您想知道为什么Python会同时具有任何非偷窃功能,那么您只需要考虑一个不那么琐碎的情况即可。如果您想将该项目放入两个元组而不是一个中,该怎么办?或者,如果您想将其放在一个元组中,但又将其存储在C静态指针中,某个模块的全局变量中或其他地方?如果要将引用计数存储在两个位置,则希望将其增加2,而当您的局部变量消失时,引用计数将减少1。对于只是创建某些东西并立即将其移交的非常简单的情况,引用窃取函数使您可以避免单引号和一引号的使用,并且对单行代码很好用和方便。但是对于任何更复杂的事情,这都是没有意义的。
打开App,查看更多内容
随时随地看视频慕课网APP

相关分类

Python