我的python代码一直崩溃,错误' GC对象已经跟踪过' 。试图找出调试此崩溃的最佳方法。
操作系统:Linux。
以下文章中有几点建议。 Python memory debugging with GDB
不确定哪种方法适用于作者。
发现了一些关于此的文章。但不完全回答我的问题: http://pfigue.github.io/blog/2012/12/28/where-is-my-core-dump-archlinux/
答案 0 :(得分:13)
在我的场景中找出了这个问题的原因(不一定是GC对象崩溃的唯一原因)。 我使用GDB和Core转储来调试此问题。
我有Python和C扩展代码(在共享对象中)。 Python代码使用C扩展代码注册一个Callback例程。 在某个工作流程中,来自C扩展代码的线程在Python代码中调用已注册的回调例程。
这通常可以正常工作,但是当多个线程同时执行相同的操作时,会导致崩溃并且“GC对象已被跟踪”。
同步对多线程的python对象的访问确实解决了这个问题。
感谢任何回应。
答案 1 :(得分:9)
当我们的C ++代码触发python回调时,我使用boost :: python遇到了这个问题。我偶尔会得到“GC对象已被跟踪”,程序将终止。
我能够在触发错误之前将GDB附加到进程。一个有趣的事情,在python代码中我们用回调包装回调 一个functools partial,它实际上掩盖了真正的错误发生的地方。用简单的可调用包装类替换partial后。 “GC对象已经跟踪错误”不再弹出,而是我现在只是遇到了一个段错误。
在我们的boost :: python包装器中,我们有lambda函数来处理C ++回调,lambda函数捕获了boost :: python :: object回调函数。事实证明,无论出于何种原因,在lambda的析构函数中,当销毁导致段错误的boost :: python :: object时,并不总是正确地获取GIL。
修复是不使用lambda函数,而是创建一个函数,确保在boost :: python :: object上调用PyDECREF()之前在析构函数中获取GIL。
class callback_wrapper
{
public:
callback_wrapper(object cb): _cb(cb), _destroyed(false) {
}
callback_wrapper(const callback_wrapper& other) {
_destroyed = other._destroyed;
Py_INCREF(other._cb.ptr());
_cb = other._cb;
}
~callback_wrapper() {
std::lock_guard<std::recursive_mutex> guard(_mutex);
PyGILState_STATE state = PyGILState_Ensure();
Py_DECREF(_cb.ptr());
PyGILState_Release(state);
_destroyed = true;
}
void operator ()(topic_ptr topic) {
std::lock_guard<std::recursive_mutex> guard(_mutex);
if(_destroyed) {
return;
}
PyGILState_STATE state = PyGILState_Ensure();
try {
_cb(topic);
}
catch(error_already_set) { PyErr_Print(); }
PyGILState_Release(state);
}
object _cb;
std::recursive_mutex _mutex;
bool _destroyed;
};
答案 2 :(得分:6)
问题是你试图将对象添加到Python的循环垃圾收集器跟踪两次。
结帐this bug,具体来说:
长话短说:如果您设置了Py_TPFLAGS_HAVE_GC
并且您正在使用Python的内置内存分配(标准tp_alloc
/ tp_free
),那么您就不会这样做必须手动拨打PyObject_GC_Track()
或PyObject_GC_UnTrack()
。 Python背后处理它。
不幸的是,目前还没有很好地记录这一点。一旦您解决了问题,请随时查看有关此行为的更好文档的错误报告(上面链接)。