PyArray_SimpleNewFromData - PullRequest
       2

PyArray_SimpleNewFromData

0 голосов
/ 10 октября 2018

Итак, я пытаюсь написать функцию C, которая принимает объект массива numpy, извлекает данные, выполняет некоторые манипуляции и возвращает другой массив c в виде объекта массива numpy.Все работает без проблем, и я использую оболочки Python, которые помогают легко манипулировать на стороне Python.Тем не менее, я сталкиваюсь с утечкой памяти.У меня есть выходной указатель типа double, который я malloc-ed и который я обертываю в объект массива 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;

Однако это создает утечку памяти, потому что данныеникогда не освобождается, и я сделал несколько поисков в Google, чтобы найти, что это проблема в таких приложениях, и решение нетривиально.Самый полезный ресурс, который я нашел на этом, это , приведенный здесь .Я не смог реализовать деструктор, о котором говорит эта страница, из данного примера.Может кто-то помочь мне с этим?Более конкретно, я ищу что-то вроде

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;

1 Ответ

0 голосов
/ 10 октября 2018

Техника, описанная в ссылке, которую вы не поняли, хороша: создайте объект Python, который знает, как освободить вашу память при уничтожении, и сделайте его основой возвращаемого массива.

ЭтоПохоже, вы были поражены сложностью создания нового типа расширения.К счастью, это не обязательно.Python поставляется с типом, предназначенным для выполнения произвольной очистки уровня C при уничтожении: капсул , которые связывают вместе указатель и функцию деструктора и вызывают деструктор при разрушении капсулы.

Toсоздайте капсулу для вашей памяти, во-первых, мы определяем функцию деструктора:

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.

И это должно гарантировать, что ваша память получаетосвобожден, когда он больше не используется.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...