Python中的C扩展 - 返回Py_BuildValue()内存泄漏问题

时间:2011-04-01 03:42:01

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

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

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是我从前面描述的函数“MyCModule”得到的C扩展名“MyCFunction”的列表和整数。

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

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

......我在这里错过了什么?有人能帮助我吗?

2 个答案:

答案 0 :(得分:11)

如果查看Py_BuildValuehttp://docs.python.org/3/c-api/arg.html#c.Py_BuildValue)的文档,可以看到在O类型规范下,它表示传入的对象的引用计数增加1 (注意:该页面的前一部分描述了O的{​​{1}}类型代码,其中增加引用计数,但此处也不相关。“ / p>

因此,在致电PyArg_ParseTuple后,您的列表的引荐计数为Py_BuildValue,但您只希望它为2

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

您应该检查lst电话的结果,因为如果Py_BuildValue失败(即返回num),您还需要释放Py_BuildValue

答案 1 :(得分:2)

感谢您将Ignacio清理干净,现在它非常有意义!最后,解决方案是,而不是直接返回Py_BuildValue,执行:

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

它就像一个魅力!