c++到python的swig导致内存泄漏!与Py_BuildValue和SWIG_NewPointerObj相关

1 投票
1 回答
1219 浏览
提问于 2025-04-15 23:26

我有一段Swig代码,导致了内存泄漏。

  PyObject* FindBestMatch(const Bar& fp) {
    Foo* ptr(new Foo());
    float match;

    // call a function to fill the foo pointer

    return Py_BuildValue(
        "(fO)",
        match,
        SWIG_NewPointerObj(ptr,
                           SWIGTYPE_p_Foo,
                           0 /* own */));
  }

我发现ptr没有被正确释放。所以我做了以下修改:

  PyObject* FindBestMatch(const Bar& fp) {
    Foo* ptr(new Foo());
    float match;

    // call a function to fill the foo pointer

    *PyObject *o = SWIG_NewPointerObj(ptr,
                       SWIGTYPE_p_Foo,
                       1 /* own */);*  <------- 1 means pass the ownership to python
    PyObject *result = Py_BuildValue("(fO)", match, o);
    Py_XDECREF(o);
    return result;
  }

但我不太确定这样做会不会导致内存损坏。在这里,Py_XDECREF(o)会减少引用计数,这样可以释放对象“o”占用的内存。但是o是返回值“result”的一部分。释放“o”可能会导致数据损坏,我猜?

我试了我的修改,效果很好,调用者(Python代码)也看到了预期的数据。但这可能是因为没有其他人覆盖那个内存区域。

那么,处理上面代码的内存管理的正确方法是什么呢?我查了Swig的文档,但没有看到很具体的描述。

请帮帮我!

谢谢,

xin

1 个回答

0

根据SWIG自动生成的代码,对于分配新对象的函数,正确的做法是把Python的所有权标志设置为1,这意味着:这个指针归Python所有
这样说是有道理的:你的new Foo()对象在哪里被释放呢?SWIG的包装对象会处理这个问题。

PyObject* FindBestMatch(const Bar& fp) {
    Foo* ptr(new Foo());
    float match;

    // call a function to fill the foo pointer

    PyObject* o = SWIG_NewPointerObj(ptr,
                   SWIGTYPE_p_Foo,
                   SWIG_BUILTIN_INIT |  0);

    PyObject* result = Py_BuildValue("(fO)", match, o);
    return result;
}

不过,我不明白为什么要减少o的引用计数:如果我没记错的话,当把一个对象传给元组或列表时,引用是被“偷走”的。

撰写回答