我有一个巨大的内存泄漏问题涉及我正在开发的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中使用它时,这只会导致分段错误(可能是因为垃圾收集者做了他的工作)...
......我在这里错过了什么?有人能帮助我吗?
答案 0 :(得分:11)
如果查看Py_BuildValue
(http://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
它就像一个魅力!