【问题标题】:C-extension in Python - return Py_BuildValue() memory leak problemPython 中的 C 扩展 - 返回 Py_BuildValue() 内存泄漏问题
【发布时间】:2011-07-27 09:43:38
【问题描述】:

我有一个巨大的内存泄漏问题,涉及我正在开发的 C 扩展。在 C 语言中,我有一个名为 A 的双精度数组和一个名为 AnotherIntVariable 的 int 变量,我想将它们传递给 Python。好吧,在我的 C 扩展模块中,我执行以下操作:

int i;  
PyObject *lst = PyList_New(len_A);  
PyObject *num;  
if(!lst)  
   return NULL;  
for(i=0;i<len_A;i++){  
   num=PyFloat_FromDouble(A[i]);  
   if(!num){  
      Py_DECREF(lst);  
      return NuLL;  
   }  
   PyList_SET_ITEM(lst,i,num);  
}  
free(A);  
return Py_BuildValue("Oi",lst,AnotherIntVariable)

所以在 Python 中我收到了这个列表和这样的 int:

Pyt_A,Pyt_int=MyCModule.MyCFunction(...)

其中 Pyt_A 和 Pyt_int 是我从 C 扩展“MyCModule”和我之前描述的函数“MyCFunction”得到的列表和整数。

问题是,在 Python 中,我使用这个 Pyt_A 数组(这就是为什么我使用 Py_BuildValue 而不是简单的 return 语句来执行 INCREF 以便暂时保存这个变量垃圾收集器)但是我需要以某种方式取消引用它以释放分配的内存。问题是我多次使用 MyCFunction 函数,这会产生内存泄漏,因为我不知道如何取消引用我在 python 中得到的数组以摆脱它。

我尝试通过在代码的 C 部分而不是 Py_BuildValue("Oi",lst,AnotherIntVariable) 中执行 return lst 来返回数组,但是当我尝试在 python 中使用它时只会导致分段错误(可能是因为垃圾收藏家做了他的工作)...

...我在这里错过了什么?有人可以帮帮我吗?

【问题讨论】:

  • 在 python 中 del Pyt_A 不会 DECREF 数组并删除它吗?
  • 我试过了,但它似乎不起作用。我仍然得到我所说的内存泄漏。
  • 另外,你在 Py_BuildValue("Oi",lst,AnotherIntVariable) 之前确实有一个回报,对吧?
  • 是的,我在帖子 editing 上错过了它
  • python 中的 sys.getrefcount(Pyt_A) 是什么?

标签: python c memory extension-methods memory-leaks


【解决方案1】:

如果您查看Py_BuildValue (http://docs.python.org/3/c-api/arg.html#c.Py_BuildValue) 的文档,您可以看到在O 类型代码下,它表示传入对象的引用计数加一(注意:前面的部分在该页面中描述了PyArg_ParseTupleO 类型代码,它不会增加引用计数,但在这里也不相关)。

因此,在调用Py_BuildValue 之后,您的列表的引用计数为2,但您只希望它为1

不要直接返回Py_BuildValue的结果,而是将其保存到PyObject指针,减少lst的引用计数,然后返回你的结果。

无论如何,您都应该检查Py_BuildValue 调用的结果,因为如果Py_BuildValue 失败(即返回NULL),您还需要释放num

【讨论】:

  • 文档现在说“对象的引用计数没有增加” - 那是什么?
  • Py_BuildValue 的目标链接锚点已更改,因此链接将转到页面顶部,其中包含 PyArg_ParseTuple 格式代码。我修复了链接,并添加了关于可能令人困惑的条目的注释。
【解决方案2】:

感谢伊格纳西奥澄清它,现在它很有意义!最后,解决方案是,而不是直接返回 Py_BuildValue,而是:

free(A);  
PyObject *MyResult = Py_BuildValue("Oi",lst,AnotherIntVariable);  
Py_DECREF(lst);  
return MyResult

它就像一个魅力!

【讨论】:

    猜你喜欢
    • 2019-07-16
    • 1970-01-01
    • 2018-04-08
    • 1970-01-01
    • 1970-01-01
    • 2011-05-16
    • 1970-01-01
    • 2010-09-25
    • 2015-03-10
    相关资源
    最近更新 更多