Python CApi引用计数详细信息

2024-04-25 14:13:54 发布

您现在位置:Python中文网/ 问答频道 /正文

我在这里查看一些示例代码(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()窃取了引用(因此没有必要对其进行递减)。好吧,我明白了。然后,作者使用PySequence_SetItem()呈现了类似的代码,不会窃取引用,因此调用方必须减少ref,示例代码如下所示:

^{pr2}$

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

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创建的引用的所有权,调用方也不会减少它)??


Tags: 代码https示例new情况作者threepyobject
1条回答
网友
1楼 · 发布于 2024-04-25 14:13:54

它会导致内存泄漏。

创建对象时,它从refcount为1开始。只有当refcount为0时,对象才会被删除。

第一个示例:当您将新对象传递给一个偷取引用(取得所有权)的函数时,如PyTuple_SetItem,refcount不会增加,因此仍然是1。当元组最终被销毁并减少其所有元素时,计数将下降到0,因此它将被销毁。一切都很好。

第三个例子:当您将新对象传递给一个不偷取引用(生成新引用)的函数时,如PySequence_SetItem,refcount会增加,因此为2。当元组最终被销毁并减少其所有元素时,计数将下降到1,因此它不会被销毁。而且,既然没有人再引用它了(除非你把它存储在某个地方),就没有人可以减少它。所以泄露了。

第二个示例:当您将新对象传递给一个不窃取引用(生成新引用)的函数时,例如PySequence_SetItem,但随后对其调用Py_DECREF,则refcount将增加到2,然后递减回1。因此,当元组最终被销毁并减少其所有元素时,计数将下降到0。一切又好了。


如果您想知道Python为什么会同时使用任何非窃取函数,那么您只需要考虑一个不那么简单的情况。

如果您想将项放入两个元组而不是一个元组中怎么办?或者,如果你想把它放在元组中,同时又把它存储在一个C静态指针中,或者某个模块的全局变量中,或者其他什么地方?如果要将引用计数存储在两个位置,则需要将引用计数增加2,而当局部变量消失时,引用计数将减少1。对于一个非常简单的例子,你只需要创建一个东西,然后马上把它处理掉,引用窃取函数可以让你避免一个增量和一个减量,同时对一行代码也很友好和方便。但对于更复杂的事情,这是没有意义的。

相关问题 更多 >