如果你获得了一个借来的参考资料但没有将它归还给 Python 领域,你应该在Py_INCREF获得它时做 a ,然后在Py_DECREF你完成它之后再做 a ,还是这是多余的?例如,这个简单的例子从 中获取一个借来的引用PyDict_GetItem,用借来的引用做一些事情,然后返回NonePython 领域。在这里使用它时是否需要Py_INCREF/Py_DECREF借来的参考?static PyObject PyFoo_bar(PyFoo *self, int field){ int field = 0; PyFoo *child = NULL; if (!PyArg_ParseTuple(args, "i", &field) { return NULL; } child = PyDict_GetItem(self->children, field); // Long code omitted that works on child // Is it safe to do so without a Py_INCREF on child now followed by PY_DECREF later? // NOT returning child here - just return None Py_RETURN_NONE;}我在这里担心的是,在调用之后PyDict_GetItem,引用计数child可能会以某种方式降至零,然后在我使用它时释放。这甚至可能吗?我不这么认为,因为 GIL 没有放在这里,但我不确定。另一方面,我想知道在此处执行Py_INCREF/是否只是最佳做法Py_DECREF。也许稍后我会放弃 GIL,或者稍后决定归还孩子。Py_INCREF很便宜。例如,这样做会更好:child = PyDict_GetItem(self->children, field);Py_INCREF(child);// Long code omittedPy_DECREF(child);Py_RETURN_NONE;
1 回答
慕桂英4014372
TA贡献1871条经验 获得超13个赞
这取决于中间“长代码”的作用。如果它执行您无法控制的 Python 代码,那么该代码完全有可能访问self->childrendict 和 deletes field,此时是的,它的引用计数可以降至零。因此,您需要防止这种情况并添加 INCREF/DECREF。
请注意,任何使用child都需要读取类型对象指针,它与引用计数相邻,因此后者将被加载到同一缓存行上。对于乱序执行,INCREF/DECREF 基本上是自由操作,因此性能没有理由将它们排除在外。
我能想到的不做 INCREF 的最好理由是当“长代码”有多个退出点时(但不执行任意 python 代码或触摸self->children如上所述)。您必须为每个退出添加 DECREF,这样很可能会丢失一个退出并导致难以调试的内存泄漏。
添加回答
举报
0/150
提交
取消
