对上一次Py_Initialize前创建的对象调用Py_DecRef是否安全?
结论
就算满足你假设的「所有参与模块都正确处理Py_Finalize」的前提,你描述的跨Py_Finalize/Py_Initialize周期调用Py_DecRef释放旧对象的操作仍然不符合Python C API设计规范,是不安全的,你遇到的崩溃属于预期行为。
核心原因
Py_Finalize执行时会销毁当前Python运行时实例的所有资源:包括所有已分配的PyObject对象、GC结构、类型定义、内置对象等,无论你是否手动调用Py_IncRef增加过引用计数,这些对象占用的内存都会被全部释放,你保留的对象指针在Py_Finalize完成后就已经是野指针。- 后续调用
Py_Initialize会创建完全独立的全新Python运行时实例,和之前销毁的运行时没有任何关联,旧的对象指针对新运行时没有任何意义,对野指针执行Py_DecRef会操作无效内存,破坏新运行时的GC链表结构,自然会触发gcmodule.c里的validate_list断言失败。
适配你场景的解决方案
你的场景是.NET GC托管Python对象的生命周期,需要做如下调整:
- 每次调用
Py_Finalize之前,必须主动遍历所有托管侧持有Python对象引用的资源,全部提前调用Py_DecRef释放,同时将这些引用标记为永久失效,避免后续.NET GC触发回收时再对无效指针执行释放操作。 - 如果确实需要跨运行时周期保留数据,不能直接保留
PyObject指针,要提前将数据序列化为原生类型(比如字符串、字节数组、原生结构体等),下一次运行时初始化完成后再重新反序列化为Python对象使用。
内容的提问来源于stack exchange,提问作者LOST
相关产品推荐
相关产品推荐

