2015-09-08 5 views
0

Я ищу утечку памяти в коде кого-то другого. Я нашел:PyBuffer_New: Нужно ли мне бесплатно вручную?

def current(self): 
    ... 
    data = PyBuffer_New(buflen) 
    PyObject_AsCharBuffer(data, &data_ptr, &buflen) 
    ... 
    return VideoFrame(data, self.frame_size, self.frame_mode, 
         timestamp=<double>self.frame.pts/<double>AV_TIME_BASE, 
         frameno=self.frame.display_picture_number) 


cdef class VideoFrame: 
    def __init__(self, data, size, mode, timestamp=0, frameno=0): 
     self.data = data 
     ... 

В функции current() не free или подобное, ни в VideoFrame. Автоматически освобождается ли PyBuffer при удалении объекта VideoFrame?

ответ

2

Ответ: «это зависит: у нас недостаточно кода, чтобы рассказать по вашему вопросу». Это зависит от того, какой тип вы сказали Китону, что возвращается 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, тогда они, вероятно, будут утечки памяти ...

+0

спасибо! Кажется, автор реализовал «правильный» объект PyBuffer_New (int size) '. Также я вижу, что в 'VideoFrame'' data' определяется как 'cdef readonly data data'. Это тот случай, когда он может течь? –

+0

Просто обнаружил, что '__Pyx_GOTREF (__ pyx_t_2);' вызывается в C-файле после 'PyBuffer_New'. Поэтому я полагаю, что все правильно реализовано. –

+0

@ P.R. Я не вижу ничего, о чем я немедленно подозреваю (в том числе для «VideoFrame.data»). Хотя, очевидно, от этого трудно сказать. Инструмент выбора для обнаружения утечек памяти (по крайней мере, на Linux) - Valgrind. Прошло некоторое время с тех пор, как я действительно использовал его, поэтому я не могу дать никаких реальных советов. – DavidW

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

  • Нет связанных вопросов^_^