Где я должен поместить Py_INCREF и Py_DECREF в этот блок в расширении Python C? - PullRequest
7 голосов
/ 08 августа 2011

Всякий раз, когда я вызывал свою функцию, использование памяти увеличивалось примерно на + 10M за вызов, поэтому я думаю, что здесь есть некоторая утечка памяти.

....
PyObject *pair = PyTuple_New(2), *item = PyList_New(0);

PyTuple_SetItem(pair, 0, PyInt_FromLong(v[j]));

if(v[j] != DISTANCE_MAX && (p[j] || d[0][j])){
  jp=j;
  while(jp!=istart) {
    PyList_Append(item, PyInt_FromLong(jp));
    jp=p[jp];
  }

  PyList_Append(item, PyInt_FromLong(jp));

  PyList_Reverse(item);
}

PyTuple_SetItem(pair, 1, item);

return pair;
....

Когда я читаю document , некоторыевызовы типа

void
bug(PyObject *list)
{
    PyObject *item = PyList_GetItem(list, 0);

    PyList_SetItem(list, 1, PyInt_FromLong(0L));
    PyObject_Print(item, stdout, 0); /* BUG! */
}

должны поставить счетчики ссылок вот так

void
no_bug(PyObject *list)
{
    PyObject *item = PyList_GetItem(list, 0);

    Py_INCREF(item);
    PyList_SetItem(list, 1, PyInt_FromLong(0L));
    PyObject_Print(item, stdout, 0);
    Py_DECREF(item);
}

Итак, где я должен поместить Py_INCREF и Py_DECREF в мою функцию?

Ответы [ 2 ]

10 голосов
/ 08 августа 2011

Объекты, которые вы создаете с помощью PyInt_FromLong () и добавляете в список, должны храниться в локальной переменной.

Причиной являются правила владения : PyInt_FromLong () генерирует ссылку, которой вы владеете. При вызове PyTuple_SetItem () вы снова теряете это право собственности, потому что PyTuple_SetItem () «крадет» его у вас, поэтому вам не нужно об этом беспокоиться. Но PyList_Append () этого не делает, он увеличивает количество ссылок. Для того, чтобы объект GC'ed был корректным, вы должны освободить свое владение DECREF'ing.

Итак, вместо PyList_Append (item, PyInt_FromLong (jp)) вы делаете следующее:

PyObject * jpo = PyInt_FromLong(jp);
// do some error checking here
PyList_Append(item, jpo);
Py_DECREF(jpo);

Это заставит программу делать правильные вещи.

0 голосов
/ 08 августа 2011

Когда объект создан, его счет будет равен 1, поэтому после этого:

my_item  = PyInt_FromLong(jp)

объект в my_item будет иметь счет 1. 1. 1005 *

Когда вы сохраняетедля элемента в контейнер, счетчик ссылок на элемент увеличивается, так что элемент будет сохранен, поэтому после этого:

PyList_Append(my_list, my_item);

объект в my_item будет иметь счет 2. 2. 1011 *

Следовательно, эта строка:

PyList_Append(item, PyInt_FromLong(jp));

создаст объект с refcount 1 и сохранит его в списке, увеличив значение refcount объекта до 2.

...