我目前正在用Cython包裝一個庫。爲此,我想重新使用純C綁定的一個函數。Cython:返回一個<object> PyObject *,它會泄漏嗎?
這是基本設置:
- mylib.pxd
- old_lib.c
- old_lib.h
在mylib.pxd我做的:
cdef extern from old_lib.h:
PyObject* get_pyobject()
然後通過old_lib.c
作爲源文件我的分機:
setup(ext_modules=[Extension("mylib", sources=["mylib.pxd", "old_lib.c"])])
在mylib.pxd,我用get_pyobject
創建,我想返回像這樣一個新的對象:
cdef PyObject* ptr
ptr = get_pyobject()
return <object>ptr
這給了我所期望的行爲,但恐怕這會泄漏ptr參考。
會嗎?我感到困惑,因爲我發現(舊)引用說,你應該自己管理的PyObject *引用,並相應地調用Py_INCREF/DECREF但似乎在用Cython FAQ他們說:
注意對象的生命週期只綁定到它自己的引用,而不是任何碰巧指向它的C指針。
這是否意味着每當返回值被丟棄時,ptr
都會被垃圾收集?
在old_lib.c
流程是這樣的:
PyObject* get_pyobject()
{
PyTypedObject* typeptr = PyObject_NEW_VAR(MyType, &Type, size)
fill_attribute(typeptr->attrib)
return (PyObject*)typeptr
}
凡PyObject_NEW_VAR
Python標準庫實現(objimpl.h:196在我的版本)使用PyObject_InitVar
。因此,返回的引用是借來的引用,但是由於使用了PyObject_MALLOC
,我猜這是對這個對象的唯一引用。相關代碼:
#define PyObject_NEW_VAR(type, typeobj, n) \
((type *) PyObject_InitVar(\
(PyVarObject *) PyObject_MALLOC(_PyObject_VAR_SIZE((typeobj),(n))),\
(typeobj), (n)))
編輯: 我已經檢查,並使用上面的代碼時,sys.getrefcount
返回3.所以,據我瞭解,當我創建的對象,它帶有的1引用計數然後,當它投射到object
時,它的引用計數被碰撞到2.它將永遠不會被垃圾收集(除非有一種方法去除只有一個可訪問指針的對象的兩個refcount)並且泄漏。 如果我插入一個PY_DECREF,它仍然有效並正確返回2.我還需要時間來直接重寫功能在用Cython,並返回2.
您可以查找並打印'PyObject'在用Cython的'ob_refcnt'領域。我會仔細檢查它的設置,因爲你認爲它應該是在得出任何明確的結論之前(我認爲你錯了代碼沒有內存泄漏,但我不確定 - 看看http:/ /tiran.bitbucket.org/python-lcov/Objects/object.c.gcov.html('PyObject_InitVar'特別'_Py_NewReference'它調用)) – DavidW
感謝您的見解。事實上,我的物體在泄漏。如果有人能提出一個很好的解釋,我會很高興接受它! – Urukann