我在其他人的代码中搜索内存泄漏。我找到了:
[
{'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
吗?
答案 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*
,那么他们可能会泄露记忆......