在PythonC扩展的这个块上,我应该将Pyúu INCREF和Pyúu DECREF放在哪里?

2024-10-04 13:15:55 发布

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

每当我调用我的函数时,每次调用的内存使用量都会增加大约+10M,因此我认为这里存在一些内存泄漏。

....
PyObject *pair = PyTuple_New(2), *item = PyList_New(0);

PyTuple_SetItem(pair, 0, PyInt_FromLong(v[j]));

if(v[j] != DISTANCE_MAX && (p[j] || d[0][j])){
  jp=j;
  while(jp!=istart) {
    PyList_append(item, PyInt_FromLong(jp));
    jp=p[jp];
  }

  PyList_Append(item, PyInt_FromLong(jp));

  PyList_Reverse(item);
}

PyTuple_SetItem(pair, 1, item);

return pair;
....

当我读到document时,有些电话

void
bug(PyObject *list)
{
    PyObject *item = PyList_GetItem(list, 0);

    PyList_SetItem(list, 1, PyInt_FromLong(0L));
    PyObject_Print(item, stdout, 0); /* BUG! */
}

需要像这样设置引用计数

void
no_bug(PyObject *list)
{
    PyObject *item = PyList_GetItem(list, 0);

    Py_INCREF(item);
    PyList_SetItem(list, 1, PyInt_FromLong(0L));
    PyObject_Print(item, stdout, 0);
    Py_DECREF(item);
}

那么,我应该把PyúINCREF和PyúDECREF放在哪里呢?


Tags: 内存pynewitembuglistpyobjectjp
2条回答

创建对象时,其refcount将为1,因此在此之后:

my_item  = PyInt_FromLong(jp)

位于my_item的对象的refcount为1。

将项目存储到容器中时,该项目的引用计数将递增,以便保留该项目,因此在此之后:

PyList_Append(my_list, my_item);

位于my_item的对象的refcount为2。

因此,这一行:

PyList_Append(item, PyInt_FromLong(jp));

将创建一个refcount为1的对象并将其存储在列表中,从而将该对象的refcount递增为2。

使用PyInt_FromLong()创建并添加到列表中的对象应保存在局部变量中。

原因是ownership rules:PyInt_FromLong()生成您自己的引用。在对PyTuple_SetItem()的调用中,您再次失去了这个所有权,因为PyTuple_SetItem()从您“窃取”了它,所以您不必在意。但是PyList_Append()没有这样做,它增加了refcount。为了正确地对对象进行GC,您必须通过递减来释放您的所有权。

因此,您可以执行以下操作,而不是PyList_Append(item,PyInt_FromLong(jp)):

PyObject * jpo = PyInt_FromLong(jp);
// do some error checking here
PyList_Append(item, jpo);
Py_DECREF(jpo);

这将使程序做正确的事情。

相关问题 更多 >