PyBuffer_New:我需要手动免费吗?

时间:2015-09-08 20:33:19

标签: memory-leaks cython pybuffer

我在其他人的代码中搜索内存泄漏。我找到了:

[
    {'count': 2, 'latest_date': datetime.datetime(2015, 9, 8, 20, 8, 40, 687936, tzinfo=<UTC>), 'my_integer': 1},
    {'count': 2, 'latest_date': datetime.datetime(2015, 9, 8, 20, 10, 20, 906069, tzinfo=<UTC>), 'my_integer': 2},
    {'count': 1, 'latest_date': datetime.datetime(2015, 9, 8, 20, 8, 58, 472077, tzinfo=<UTC>), 'my_integer': 3}
]

功能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吗?

1 个答案:

答案 0 :(得分:2)

答案是:&#34;它取决于;我们没有足够的代码来解答您的问题。&#34;它由你告诉Cython checkbox返回的类型来管理。我将给出两个简化的说明案例,希望你能够解决更复杂的案例。

如果你告诉Cython它是PyBuffer_New它没有该类型的天生知识,并且没有做任何事情来跟踪记忆:

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); } 并查看任务管理器,您可以看到内存使用量跳了起来但没有返回。

或者,如果你告诉Cython它是test(),让Cython像任何其他Python对象一样处理它,并正确管理引用计数:

object

然后

生成循环的代码
# 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*,那么他们可能会泄露记忆......