调试Python致命错误:GC对象已被跟踪

Fer*_*eru 15 python crash garbage-collection

我的python代码崩溃了,错误'GC Object has tracked'.试图找出调试此崩溃的最佳方法.

操作系统:Linux.

  • 有没有正确的方法来调试此问题.

以下文章中有几点建议. 使用GDB进行Python内存调试

不确定哪种方法适用于作者.

  • 有没有办法在这种可以分析的场景中生成内存转储.就像在Windows世界中一样.

找到一些关于此的文章.但不完全回答我的问题:http: //pfigue.github.io/blog/2012/12/28/where-is-my-core-dump-archlinux/

Fer*_*eru 13

在我的场景中找出了这个问题的原因(不一定是GC对象崩溃的唯一原因).我使用GDB和Core转储来调试此问题.

我有Python和C扩展代码(在共享对象中).Python代码使用C扩展代码注册一个Callback例程.在某个工作流程中,来自C扩展代码的线程在Python代码中调用已注册的回调例程.

这通常可以正常工作,但是当多个线程同时执行相同的操作时,会导致崩溃并且"GC对象已经被跟踪".

同步对多线程的python对象的访问确实解决了这个问题.

感谢任何回应.

  • 如何在此上下文中同步访问? (4认同)

小智 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;
};
Run Code Online (Sandbox Code Playgroud)


Chr*_*ger 6

问题是您尝试将对象添加到Python的循环垃圾收集器跟踪两次.

看看这个bug,具体来说:

简而言之:如果你设置Py_TPFLAGS_HAVE_GC并使用Python的内置内存分配(标准tp_alloc/ tp_free),则无需手动调用PyObject_GC_Track()PyObject_GC_UnTrack().Python在你背后处理它.

不幸的是,目前还没有很好地记录这一点.一旦您解决了问题,请随时查看有关此行为的更好文档的错误报告(上面链接).