答案是:“视情况而定;我们没有足够的代码来判断您的问题。” 它取决于您告诉 CythonPyBuffer_New
返回的类型。我将给出两个简化的说明案例,希望您能够为更复杂的案例解决问题。
如果您告诉 Cython 它是 aPyObject*
它没有该类型的先天知识,并且不会做任何事情来跟踪内存:
# 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
for 变量在这两种情况之间跳转(例如在 的定义中VideoFrame
)。如果他们PyObject*
不小心使用DECREF
s 那么他们可能会泄漏内存......