猿问

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

如果你获得了一个借来的参考资料但没有将它归还给 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 omitted

Py_DECREF(child);

Py_RETURN_NONE;


开心每一天1111
浏览 223回答 1
1回答

慕桂英4014372

这取决于中间“长代码”的作用。如果它执行您无法控制的 Python 代码,那么该代码完全有可能访问self->childrendict 和 deletes field,此时是的,它的引用计数可以降至零。因此,您需要防止这种情况并添加 INCREF/DECREF。请注意,任何使用child都需要读取类型对象指针,它与引用计数相邻,因此后者将被加载到同一缓存行上。对于乱序执行,INCREF/DECREF 基本上是自由操作,因此性能没有理由将它们排除在外。我能想到的不做 INCREF 的最好理由是当“长代码”有多个退出点时(但不执行任意 python 代码或触摸self->children如上所述)。您必须为每个退出添加 DECREF,这样很可能会丢失一个退出并导致难以调试的内存泄漏。
随时随地看视频慕课网APP

相关分类

Python
我要回答