2011-09-08 45 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'可能会给你一些线索 –