为了账号安全,请及时绑定邮箱和手机立即绑定

Python C 扩展是否需要 Py_INCREF 借用的参考,如果不将其返回给

Python C 扩展是否需要 Py_INCREF 借用的参考,如果不将其返回给

开心每一天1111 2022-07-05 17:13:13
如果你获得了一个借来的参考资料但没有将它归还给 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,这样很可能会丢失一个退出并导致难以调试的内存泄漏。


查看完整回答
反对 回复 2022-07-05
  • 1 回答
  • 0 关注
  • 222 浏览
慕课专栏
更多

添加回答

举报

0/150
提交
取消
微信客服

购课补贴
联系客服咨询优惠详情

帮助反馈 APP下载

慕课网APP
您的移动学习伙伴

公众号

扫描二维码
关注慕课网微信公众号