我编写了一个Cython函数,它以数字的列表/类型内存视图作为参数,并返回一个相同长度的Typed Memoryview:
def test(list_data):
cdef unsigned int n = len(list_data)
cdef unsigned int i = 0
cdef double *results_arr = <double*>malloc(n* sizeof(double) )
cdef double[:] results = <double[:n]>results_arr
for i in range(n):
results[i] = 220 - list_data[i]
return results
在对其进行了几千次测试后,我开始收到Segmentation fault (core dumped)
错误。我意识到这是一个内存管理问题,但我找不到如何管理函数返回的类型化内存视图的内存的示例。我发现的唯一有用的信息是memory allocation,它建议将result_arr
的生命周期绑定到python对象并使用__dealloc__
方法释放内存。
有没有办法管理memoryview垃圾收集,而不涉及创建用于释放内存的python类?
编辑: 我试过这个,似乎是以正确的方式释放内存。
def test(list_data):
cdef unsigned int n = len(list_data)
cdef unsigned int i = 0
cdef double *arr = <double*>malloc(n* sizeof(double) )
if not arr:
raise MemoryError()
cdef double[:] results = <double[:n]>arr
for i in range(n):
results[i] = 220 - list_data[i]
free(arr)
return results
为什么这样做并且有更好的方法来管理内存?
答案 0 :(得分:1)
类型化的内存视图就像名称暗示了memorybuffer的视图一样。它不拥有那段内存,但提供了一种有效的访问方式。您引用的cython文档的一部分是将底层堆分配的c-array绑定到python垃圾收集器的方法。 如果你想像在这里一样使用c内存分配,你也必须对它负责。这是因为你现在正在进行c级工作,而且c对你免费做任何事。您的函数会查看已分配的内存,但会丢弃引用它的指针。现在,这种记忆无所事事地负责解放它。
如果您不想进入c世界,我建议您将数据读入python中的numpy数组,并将此数组传递给cython函数。 Python和numpy非常适合这种事情。
但是如果你想使用malloc,另一种选择可能是将它包装在扩展类型中。
cdef class mymemory:
cdef:
double *arr
double[::1] results
def __cinit__(self, int n):
self.arr = <double*>malloc(n*sizeof(double))
def __init__(self, int n):
self.results = <double[:n]> arr
"""
Some code for filling in the results.
"""
def __dealloc(self):
if self.arr != NULL:
free(self.arr)
现在,当mymemory被垃圾收集时,底层c数组将被释放。这是一个替代方案,因为你要求它,但我仍然建议numpy这个。
在你的第二个函数上,你似乎分配内存,创建一个视图,然后再次释放它。现在这个memoryview正在查看的内存不再存在。所以你是对的,内存是正确释放的。但是现在,对于你来说,内存视图已经不再有用了。