2011-04-01 2 views
7

У меня проблема с утечкой памяти, связанная с расширением C, которое я разрабатываю. В C у меня есть массив удвоений, называемый A, и переменная int, называемая AnotherIntVariable, которую я хочу передать Python. Ну, в моем модуле C-расширения я делаю следующее:C-extension в Python - возвращает проблему с утечкой памяти Py_BuildValue()

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 являются список и целое число Я получаю от моего C-расширения «MyCModule», от функции «MyCFunction», которую я описал ранее.

Проблема заключается в том, что в Python, я использую этот Pyt_A массив (так вот почему я использую Py_BuildValue вместо простого return заявление, чтобы сделать INCREF для того, чтобы сохранить эту переменную на мгновение от сборщика мусора), но то мне нужно как-то разыменовать его, чтобы освободить выделенную память. Проблема в том, что я использую функцию MyCFunction несколько раз, и это вызывает утечку памяти, потому что я не знаю, как разыменовать массив, который я получаю на python, чтобы избавиться от него.

Я пытался просто возвращая массив, выполнив return lst в C части кода вместо Py_BuildValue("Oi",lst,AnotherIntVariable), но это только приводит к Segmentation Fault при попытке использовать его в питон (вероятно, потому что сборщик мусора сделал его работа) ...

... что я здесь не хватает? Кто-нибудь может мне помочь?

+0

не del Pyt_A в python DECREF массива и удалить его? – highBandWidth

+0

Я попробовал, но он, похоже, не работает. Я все еще получаю эту утечку памяти, о которой я говорю. –

+1

Кроме того, у вас есть возврат до Py_BuildValue («Oi», lst, AnotherIntVariable) правильно? – highBandWidth

ответ

11

Если вы посмотрите на документацию для Py_BuildValue (http://docs.python.org/3/c-api/arg.html#c.Py_BuildValue) вы можете увидеть, что под O TypeCode, это говорит о том, что счетчик ссылок переданному в объекте увеличивается на единицу (Примечание: ранний раздел в этой странице описывается O typecode для PyArg_ParseTuple, который не увеличивает счетчик ссылок, но также не имеет значения здесь).

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

Вместо того, чтобы возвращать результат Py_BuildValue непосредственно, сохраните его до указателя PyObject, уменьшите счетчик ссылок lst, а затем верните результат.

Вы должны проверять результат Py_BuildValue вызова в любом случае, так как вы должны освободить num в том случае, если Py_BuildValue терпит неудачу (т.е. возвращает NULL).

+0

В документации теперь говорится: «Счетчик ссылок объекта не увеличивается» _ - так что это такое? – Eric

+1

Изменен привязку целевой ссылки для 'Py_BuildValue', поэтому ссылка переместилась в начало страницы, которая охватывает коды формата' PyArg_ParseTuple'. Я исправил ссылку и добавил заметку о потенциально запутанной записи. – ncoghlan

2

Спасибо, что расчистил его Игнасио, теперь он имеет такой смысл! Наконец, решение было, вместо того, чтобы вернуться непосредственно Py_BuildValue, сделать:

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

Он работал как шарм!

Смежные вопросы