为了账号安全,请及时绑定邮箱和手机立即绑定

Python CApi参考计数详细信息

Python CApi参考计数详细信息

慕容3067478 2021-04-08 10:15:14
我在这里查看一些示例代码(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)?
查看完整描述

1 回答

?
慕的地6264312

TA贡献1817条经验 获得超6个赞

这会导致内存泄漏。

创建对象时,它的引用计数为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。对于只是创建某些东西并立即将其移交的非常简单的情况,引用窃取函数使您可以避免单引号和一引号的使用,并且对单行代码很好用和方便。但是对于任何更复杂的事情,这都是没有意义的。


查看完整回答
反对 回复 2021-04-27
  • 1 回答
  • 0 关注
  • 182 浏览
慕课专栏
更多

添加回答

举报

0/150
提交
取消
意见反馈 帮助中心 APP下载
官方微信