PyArray_SimpleNewFromData

时间:2018-10-10 02:48:29

标签: python c python-3.x numpy

因此,我试图编写一个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;
  

2 个答案:

答案 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);