我应该把 Py_INCREF 和 Py_DECREF 放在 Python C 扩展中这个块的哪里?
每当我调用我的函数时,每次调用的内存使用量都会增加大约+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;
....
当我阅读 文档 时,有些调用需要
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 放在我的函数中的哪里?
Whenever I called my function, memory usage is increased around +10M per call, so I think there is some memory leak here.
....
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;
....
When I read document, some calls like
void
bug(PyObject *list)
{
PyObject *item = PyList_GetItem(list, 0);
PyList_SetItem(list, 1, PyInt_FromLong(0L));
PyObject_Print(item, stdout, 0); /* BUG! */
}
need to put reference counts like this
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);
}
So, Where should I put Py_INCREF and Py_DECREF on my function?
如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。
绑定邮箱获取回复消息
由于您还没有绑定你的真实邮箱,如果其他用户或者作者回复了您的评论,将不能在第一时间通知您!
发布评论
评论(2)
使用 PyInt_FromLong() 创建并添加到列表中的对象应保存在局部变量中。
原因是 所有权规则: PyInt_FromLong() 生成一个引用,您可以使用自己的。在对 PyTuple_SetItem() 的调用中,您再次失去了此所有权,因为 PyTuple_SetItem() 从您那里“窃取”了它,因此您不必关心。但 PyList_Append() 不会这样做,它会增加引用计数。为了正确地对对象进行 GC,您必须通过 DECREF'ing 释放您的所有权。
因此,您可以执行以下操作,而不是 PyList_Append(item, PyInt_FromLong(jp)):
这将使程序执行正确的操作。
The objects you create with PyInt_FromLong() and you add to the list should be kept in a local variable.
The reason are the ownership rules: PyInt_FromLong() generates a reference that you own. In the call to PyTuple_SetItem(), you lose this ownership again, because PyTuple_SetItem() "steals" it from you, so you don't have to care about. But PyList_Append() doesn't do so, it increases the refcount. In order to have the object GC'ed correctly, you have to release your ownership by DECREF'ing.
So, instead of PyList_Append(item, PyInt_FromLong(jp)), you do the following:
This will make the program do the right thing.
创建对象时,其引用计数将为 1,因此在此之后:
my_item
处的对象的引用计数将为 1。当您将项目存储到容器中时,该项目的引用计数会增加,因此该项目将被保留,因此在此之后:
my_item
处的对象的引用计数将为 2。因此,这一行:
将创建一个引用计数为 1 的对象并将其存储在列表中,将对象的引用计数增加到 2。
When an object is created, its refcount will be 1, so after this:
the object at
my_item
will have a refcount of 1.When you store an item into a container, the item's reference count is incremented so that the item will be retained, so after this:
the object at
my_item
will have a refcount of 2.Therefore, this line:
will create an object with refcount 1 and store it in the list, incrementing the object's refcount to 2.