我正在查看这里的一些示例代码( 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 )??
发布于 2018-07-09 08:20:21
它会导致内存泄漏。
创建对象时,它从refcount为1开始。只有当refcount变为0时,该对象才会被删除。
第一个示例引用:当您将新对象传递给一个可以窃取引用(取得所有权)的函数(如PyTuple_SetItem
)时,引用计数不会递增,因此它仍然是1。当元组最终被销毁并对其所有元素进行反引用时,计数将下降到0,因此它将被销毁。一切都很好。
第三个示例:当您将新对象传递给不窃取引用(创建新引用)的函数(如PySequence_SetItem
)时,引用计数将递增,因此它是2。当元组最终被销毁并对其所有元素进行反引用时,计数将降至1,因此它不会被销毁。而且,由于没有其他人再引用它(除非您将它存储在某个地方),所以任何人都不可能破坏它。所以它被泄露了。
第二个示例:当您将新对象传递给不窃取引用(创建新引用)的函数(如PySequence_SetItem
),但随后对其调用Py_DECREF
时,引用计数将递增为2,并递减回1。因此,当元组最终被销毁并对其所有元素进行解引用时,引用计数将降至0。一切又好起来了。
如果你想知道为什么Python会同时使用非窃取函数,你只需要考虑一个不那么简单的例子。
如果您想将项目放在两个元组中而不是一个元组中,该怎么办?或者,如果你想把它放在一个元组中,但也要把它存储在一个C静态指针中,或者存储在某个模块的全局变量中,或者其他什么地方?如果你想把引用计数放在两个地方,你希望它增加2,当你的局部变量消失时,它们又减少了1。对于真正简单的情况,您只是创建一些东西并立即将其传递出去,引用窃取函数可以让您避免这种一步一个脚印的情况,而且对于一行代码也很好和方便。但对于更复杂的情况,这是没有意义的。
https://stackoverflow.com/questions/51236885
复制相似问题