如果你獲得了一個借來的參考資料但沒有將它歸還給 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
提交
取消
