Я вызываю метод Python из C, и через 10 часов он вызывает ошибку утечки / сегментации на PyObject_CallMethod.
Можете ли вы просмотреть мой код? Где моя ошибка? Что-то не хватает?
Код C:
PyObject *pFrameAsList = PyList_New(0);
...
for (int k=0; k<m_nbImages; ++k)
{
PyObject *pFrameAsArray = toNDArray(frame);
...
PyList_Append(pFrameAsList, pFrameAsArray);
Py_DECREF(pFrameAsArray);
}
PyObject *pValue = PyObject_CallMethod(pInstance, "analyseFrame", "(O)", pFrameAsList);
...
Py_INCREF(pValue);
...
for (int k=0 ; k<max; k++ )
{
PyObject *ptemp = PyList_GetItem(pValue,k);
}
Py_DECREF(pFrameAsList);
Py_DECREF(pValue);
И код Python:
def analyseFrame(self, frame):
results = self.model.analyse(np.asarray(frame))
return list(results)
Т.е. вы должен проверяете возвращаемое значение PyList_New, toNDArray, PyList_Append, PyObject_CallMethod и те времена max для PyList_GetItem; в этом случае могло случиться так, что ваш код не аварийно завершился, но завершился бы с ошибкой MemoryError.
С вами все в порядке, проверьте возвращаемое значение / код - это лучшая практика, и это делается в нашем коде, но я убираю здесь проверки, чтобы уменьшить код.
как мы можем проверить правильность этих проверок ошибок, если вы их не показываете!






Я считаю, что проблема в том, что у вас не должно быть следующей строки:
Py_INCREF(pValue)
Причина в том, что PyObject_CallMethod уже увеличил для вас счетчик ссылок. Если вы выполните дополнительный вызов Py_INCREF, счетчик ссылок для данного PyObject никогда не опустится до 0.
Согласно документации, PyObject_CallMethod возвращает новую ссылку.
Чтобы понять значение "новая ссылка", в отличие от "заимствованная ссылка", посмотрите первый абзац раздела Сведения о количестве ссылок документации:
Если я удалю Py_INCREF (pValue), я сразу выделю ошибку. Спасибо за ссылку, буду читать.
Я сделал обзор по новым / заимствованным ссылкам в соответствии с вашим комментарием и ссылкой. Я удаляю Py_INCREF во всех методах, возвращающих заимствованные ссылки. Я тестирую ...
Мне не кажется правильным, основываясь на документации, что вызывающий должен будет выполнить Py_INCREF для возвращаемого значения из PyObject_CallMethod, потому что эта возвращенная ссылка считается «новой», а не «заимствованной». Возможно, вы передаете pValue в качестве аргумента какой-то функции, которая «крадет» ссылку? Понятие «кража» ссылки задокументировано в той же ссылке с указанием количества ссылок, которую я разместил в ответе.
Как предложено в stackoverflow.com/questions/510406/…, вы также можете использовать sys.getrefcount (pValue) в различных точках вашего кода, чтобы узнать, какой текущий счетчик ссылок в различных местах вашего кода.
Вам не хватает проверка ошибок везде! Они не являются «необязательными» с C-API ...