You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

如何在SWIG中为扩展C结构体建立引用关系避免Python GC崩溃

解决方案:让Room持有House的Python引用以保证GC顺序

要解决Python GC无法保证Room先于House销毁的问题,核心是让每个Room的Python实例持有对应House的引用,这样Python的垃圾回收机制会确保House只有在所有关联的Room都被销毁后,才会被回收。以下是具体的SWIG代码修改方案:

修改example.i中的Room扩展部分

%module example
%include "cmalloc.i"

%{
#include "objs.h"
#include <Python.h>
%}

%include "objs.h"

%extend House {
    House(const char * address){
        struct House * house = create_house(address);
        return house;
    }
    ~House(){
        delete_house($self);
    }
}

%extend Room {
    Room(PyObject *house_obj, int sqft){
        struct House *house;
        // 将Python的House对象转换为C指针,验证类型合法性
        if (!SWIG_ConvertPtr(house_obj, (void**)&house, SWIGTYPE_p_House, 0)) {
            struct Room *room = create_room(house, sqft);
            // 让Room的Python实例持有House的引用,防止House被提前回收
            PyObject_SetAttrString($self, "_house_ref", house_obj);
            Py_INCREF(house_obj); // 增加引用计数,确保House存活至Room销毁
            return room;
        }
        // 类型错误时抛出Python异常
        PyErr_SetString(PyExc_TypeError, "First argument must be a House instance");
        return NULL;
    }
    ~Room(){
        // 先释放Room的C资源
        delete_room($self);
        // 释放持有的House引用,避免内存泄漏
        PyObject *house_ref = PyObject_GetAttrString($self, "_house_ref");
        if (house_ref) {
            Py_DECREF(house_ref);
        }
    }
}

代码说明

  1. 构造函数修改:

    • 将Room构造函数的第一个参数改为PyObject* house_obj,直接操作传入的Python House实例,而非仅转换后的C指针。
    • 用SWIG_ConvertPtr验证传入对象为House类型并转换为C指针,用于调用create_room创建Room实例。
    • 通过PyObject_SetAttrString给Room的Python实例添加隐藏属性_house_ref,保存House的Python对象,同时调用Py_INCREF增加引用计数,确保House在Room存在期间不会被GC回收。
  2. 析构函数修改:

    • 销毁Room的C资源后,获取_house_ref属性并调用Py_DECREF减少引用计数。当所有Room都释放引用后,House的引用计数降至0,GC才会回收House并调用其析构函数。

额外注意事项

  • 避免双重释放:调用delete_house时,C库会自动销毁所有关联的Room。若对应的Python Room实例仍存在,其析构函数调用delete_room会触发段错误。可在House的析构函数中遍历Room并标记C对象已失效,或在Room的析构函数中先检查C对象有效性再执行销毁操作。
  • 保护内部属性:_house_ref为内部属性,可通过SWIG的%pythoncode给Room类添加__delattr__方法禁止外部修改,或使用私有命名规范避免误操作。

内容的提问来源于stack exchange,提问作者Martin Belanger

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.07.30 01:47:56