Ответ: «это зависит: у нас недостаточно кода, чтобы рассказать по вашему вопросу». Это зависит от того, какой тип вы сказали Китону, что возвращается PyBuffer_New
. Я приведу два упрощенных иллюстративных примера, и, надеюсь, вы сможете усовершенствовать его для более сложного случая.
Если вы скажете Cython, что это PyObject*
он не имеет врожденное знание этого типа, и не делает ничего, чтобы следить памяти:
# BAD - memory leak!
cdef extern from "Python.h":
ctypedef struct PyObject
PyObject* PyBuffer_New(int size)
def test():
cdef int i
for i in range(100000): # call lots of times to allocate lots of memory
# (type of a is automatically inferred to be PyObject*
# to match the function definition)
a = PyBuffer_New(1000)
и сгенерированный код для цикла в значительной степени выглядит следующим образом:
for (__pyx_t_1 = 0; __pyx_t_1 < 1000; __pyx_t_1+=1) {
__pyx_v_i = __pyx_t_1;
__pyx_v_a = PyBuffer_New(1000);
}
Т.е. память выделяется, но не освобождается. Если вы запустите test()
и посмотрите на диспетчер задач, вы можете увидеть, как использование памяти прыгает вверх и не возвращается.
В качестве альтернативы, если вы скажете Cython это в object
, что позволяет Cython сделку с ним, как и любой другой объект Python, и правильно управлять счетчик ссылок:
# Good - no memory leak
cdef extern from "Python.h":
object PyBuffer_New(int size)
def test():
cdef int i
for i in range(100000):# call lots of times to allocate lots of memory
a = PyBuffer_New(1000)
Сгенерированный код цикла затем
for (__pyx_t_1 = 0; __pyx_t_1 < 100000; __pyx_t_1+=1) {
__pyx_v_i = __pyx_t_1;
__pyx_t_2 = PyBuffer_New(1000); if (unlikely(!__pyx_t_2)) {__pyx_filename = __pyx_f[0]; __pyx_lineno = 7; __pyx_clineno = __LINE__; goto __pyx_L1_error;}
__Pyx_GOTREF(__pyx_t_2);
__Pyx_XDECREF_SET(__pyx_v_a, __pyx_t_2);
__pyx_t_2 = 0;
}
Обратите внимание на DECREF
, где будет освобожден объект. Если вы запустите test()
, вы не увидите долгосрочного перехода на использование памяти.
Может быть возможно перепрыгнуть между этими двумя случаями, используя cdef
для переменной (например, в определении VideoFrame
). Если они используют PyObject*
без тщательного DECREF
s, тогда они, вероятно, будут утечки памяти ...
спасибо! Кажется, автор реализовал «правильный» объект PyBuffer_New (int size) '. Также я вижу, что в 'VideoFrame'' data' определяется как 'cdef readonly data data'. Это тот случай, когда он может течь? –
Просто обнаружил, что '__Pyx_GOTREF (__ pyx_t_2);' вызывается в C-файле после 'PyBuffer_New'. Поэтому я полагаю, что все правильно реализовано. –
@ P.R. Я не вижу ничего, о чем я немедленно подозреваю (в том числе для «VideoFrame.data»). Хотя, очевидно, от этого трудно сказать. Инструмент выбора для обнаружения утечек памяти (по крайней мере, на Linux) - Valgrind. Прошло некоторое время с тех пор, как я действительно использовал его, поэтому я не могу дать никаких реальных советов. – DavidW