2011-09-08 44 views
3

我有一個使用Python回調的C++庫。回調函數,即PyObject *,存儲在UnaryFunction類的對象中,構造函數Py_INCREFs。解析器Py_XDECREFs它。那就是問題所在。該解釋器在該DECREF上進行了段錯誤分析。爲什麼Python函數會收集垃圾?

我的解決方案是不DECREF它,但這似乎是錯誤的。 INC/DEC函數的引用計數的正確方法是什麼?更重要的是,爲什麼解釋程序在還有其他實時引用時嘗試GC函數體?

編輯:在Linux上,而不是一個段錯誤,我得到的斷言失敗,說:

python: Objects/funcobject.c:442: func_dealloc: Assertion 'g->gc.gc_refs != (-2)' failed.

+0

這似乎是郵件列表的問題。 Google「Python郵件列表」。在那裏你可以找到認識Python的人,有時甚至是Python的創建者/開發者。 –

+0

相關:http://stackoverflow.com/questions/7326762/cython-callback-works-correctly-for-function-but-not-for-bound-method/7339258#7339258 – jfs

+0

@JFSebastian,很好的猜測,但方法並沒有超出範圍。這個問題在一個簡單的平面腳本中展示,它帶有一個簡單的'def myfunc(x):「。如果我註釋掉使用回調的部分,那麼我可以在腳本的末尾調用myfunc()。 – Adam

回答

0

看樣子Py_INCREF根本沒有實際增加引用計數。

1

崩潰並不一定意味着它是試圖GC的使用對象。它也可能意味着您正在調用python代碼而沒有解釋器鎖定。

在析構函數中調用Py_XDECREF使我覺得你有這樣的事情:

void MyCallback(myfunc, myarg) 
{ 
    ... 
    PyGILState_STATE gilstate = PyGILState_Ensure(); 
    try { 
      myfunc(myarg); 
    } catch (...) { 
     ... 
    } 
    PyGILState_Release(gilstate); 

    // myfunc goes out of scope here --> CRASH because we no longer own the GIL 
} 

與簡單的解決方案:

... 
try { 
    scopefunc = myfunc; 
    myfunc = emptyfunc(); 
    scopefunc(myarg); 
} ... 
+0

其實,我根本不知道GIL沒有被釋放,我的C++代碼只是簡單的使用PyEval_CallObject()來調用這個函數,我說這是收集的,因爲segfault是:Objects/funcobject.c :442:func_dealloc:斷言'g-> gc.gc_refs!=(-2)'failed.'這就是一個dealloc和GC引用 – Adam

+0

如果你只有一個線程,那麼事情應該更簡單。不匹配的incref/decref,並且在涉及該函數的每一步之前和之後調用'sys.getrefcount'可能會給你一些線索 –