【问题标题】:c++-to-python swig caused memory leak! Related to Py_BuildValue and SWIG_NewPointerObjc++-to-python swig 导致内存泄漏!与 Py_BuildValue 和 SWIG_NewPointerObj 相关
【发布时间】:2026-01-06 16:05:01
【问题描述】:

我有以下导致内存泄漏的 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 是返回值“结果”的一部分。我猜,释放“o”会导致数据损坏?

我尝试了我的改变。它工作正常,调用者(python 代码)确实看到了预期的数据。但这可能是因为没有其他人覆盖该内存区域。

那么处理上述代码的内存管理的正确方法是什么?我搜索 swig 文档,但没有看到非常具体的描述。

请帮忙!

谢谢, 辛

【问题讨论】:

  • 这里有与 python-nfqueue-bindings 代码类似的问题git.inl.fr/cgi-bin/…
  • 我在 SWIG python 代码中遇到了类似的内存泄漏问题——这是我们在项目中停止使用 SWIG 的原因之一。

标签: python swig


【解决方案1】:

根据 SWIG 为分配新对象的函数自动生成的代码,正确的方法应该是将 Python Ownership 标志设置为 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 的引用计数:如果我在将对象传递给元组或列表时没记错的话,引用被盗了。

【讨论】: