因此,我试图编写一个C函数,该函数接受numpy数组对象,提取数据,进行一些操作,然后将另一个c数组作为numpy数组对象返回。一切都可以无缝运行,并且我使用python包装器,这有助于在python方面轻松进行操作。但是,我面临着内存泄漏。我有一个输出的double指针,我将其分配并在返回到调用python函数之前包装到Python数组对象中,
PyObject *arr;
int nd = 2;
npy_intp dims[] = {5, 10};
double *data = some_function_that_returns_a_double_star(x, y, z);
arr = PyArray_SimpleNewFromData(nd, dims, NPY_DOUBLE, (void *)data);
return arr;
但是,这会造成内存泄漏,因为永远不会释放数据,因此我进行了一次谷歌搜索,发现这在此类应用程序中是个问题,解决方案也不是简单的事情。我发现的最有用的资源是given here。从给定的示例,我无法实现此页面所讨论的析构函数。有人可以帮我弄这个吗?更具体地说,我正在寻找类似的东西,
PyObject *arr;
int nd = 2;
npy_intp dims[] = {5, 10};
double *data = some_function_that_returns_a_double_star(x, y, z);
arr = PyArray_SimpleNewFromData(nd, dims, NPY_DOUBLE, (void *)data);
some_destructor_that_plug_memLeak_due_to_data_star(args);
return arr;
答案 0 :(得分:3)
您不了解的链接中描述的技术是一个很好的技术:创建一个Python对象,该对象知道如何在销毁内存时释放内存,并将其作为返回数组的基础。
听起来,创建新扩展类型的复杂性可能会让您不知所措。幸运的是,这不是必需的。 Python带有一种旨在在销毁时执行任意C级清理的类型:capsules,它将指针和析构函数捆绑在一起,并在胶囊被销毁时调用析构函数。
要为您的记忆创建一个胶囊,首先,我们定义一个析构函数:
void capsule_cleanup(PyObject *capsule) {
void *memory = PyCapsule_GetPointer(capsule, NULL);
// I'm going to assume your memory needs to be freed with free().
// If it needs different cleanup, perform whatever that cleanup is
// instead of calling free().
free(memory);
}
然后您将胶囊设置为阵列的基础
PyObject *capsule = PyCapsule_New(data, NULL, capsule_cleanup);
PyArray_SetBaseObject((PyArrayObject *) arr, capsule);
// Do not Py_DECREF the capsule; PyArray_SetBaseObject stole your
// reference.
那应该确保您的内存在不再使用时被释放。
答案 1 :(得分:1)
虽然PyCapsule
方法的工作原理更一般,但可以通过设置OWNDATA
标志来使numpy在数组被垃圾回收时为您释放数组中的内存。
double *data = some_function_that_returns_a_double_star(x, y, z);
PyObject *arr = PyArray_SimpleNewFromData(nd, dims, NPY_DOUBLE, (void *)data);
PyArray_ENABLEFLAGS((PyArrayObject*) arr, NPY_ARRAY_OWNDATA);