jmd*_*_dk 10 python memory free cython memoryview
在Cython代码中,我可以分配一些内存并将其包装在内存视图中,例如:
cdef double* ptr
cdef double[::1] view
ptr = <double*> PyMem_Malloc(N*sizeof('double'))
view = <double[:N]> ptr
Run Code Online (Sandbox Code Playgroud)
如果现在我使用释放内存PyMem_Free(ptr),则尝试访问元素之类ptr[i]的错误将导致错误。但是,我可以安全地尝试访问view[i](尽管它不会返回原始数据)。
我的问题是:仅释放指针总是安全吗?是否以某种方式通知内存视图对象已释放内存,还是应该以某种方式手动删除视图?此外,即使内存视图引用了内存,也可以保证释放内存吗?
它需要深入研究C代码才能显示出来,但是:
该行view = <double[:N]> ptr实际上会生成一个__pyx_array_obj。此类型与文档中cython.view.array详述的“ Cython数组”相同,可导入为。Cython数组确实有一个称为的可选成员callback_free_data,可以充当析构函数。
该行翻译为:
struct __pyx_array_obj *__pyx_t_1 = NULL;
# ...
__pyx_t_1 = __pyx_array_new(__pyx_t_2, sizeof(double), PyBytes_AS_STRING(__pyx_t_3), (char *) "c", (char *) __pyx_v_ptr);
Run Code Online (Sandbox Code Playgroud)
(__pyx_t_2和__pyx_t_3只是分别存储大小和格式的临时文件)。如果我们查看内部,__pyx_array_new我们首先会看到数组的data成员被直接分配给传递为__pyx_v_ptr
__pyx_v_result->data = __pyx_v_buf;
Run Code Online (Sandbox Code Playgroud)
(即未制作副本),其次callback_free_data未设置。旁注:的C代码cython.view.array实际上是从Cython代码生成的,因此,如果您想进一步研究,它可能比生成的C更容易阅读。
本质上,memoryview拥有一个cython.view.array,它具有一个指向原始数据的指针,但是没有callback_free_data设置。当memoryview死亡时,将调用的析构函数cython.view.array。这会清理一些内部信息,但不会释放它所指向的数据(因为它没有指示这样做的指示)。
因此,调用后访问memoryview 是不安全的PyMem_Free。您似乎无法摆脱的事实真是太幸运了。不过,如果您不访问它,可以安全地保留memoryview。类似的功能:
def good():
cdef double* ptr
cdef double[::1] view
ptr = <double*> PyMem_Malloc(N*sizeof('double'))
try:
view = <double[:N]> ptr
# some other stuff
finally:
PyMem_Free(ptr)
# some other stuff not involving ptr or view
Run Code Online (Sandbox Code Playgroud)
会没事的。类似的功能:
def bad():
cdef double* ptr
cdef double[::1] view
ptr = <double*> PyMem_Malloc(N*sizeof('double'))
try:
view = <double[:N]> ptr
# some other stuff
finally:
PyMem_Free(ptr)
view[0] = 0
return view
Run Code Online (Sandbox Code Playgroud)
这将是一个坏主意,因为它会传回不指向任何内容的memoryview,并view在释放其查看的数据之后进行访问。
您一定要确保PyMem_Free在某个时间进行调用,否则会发生内存泄漏。如果view被传递了,因此很难跟踪生命周期的一种方法是手动创建一个cython.view.arraywith callback_free_dataset:
cdef view.array my_array = view.array((N,), allocate_buffer=False)
my_array.data = <char *> ptr
my_array.callback_free_data = PyMem_Free
view = my_array
Run Code Online (Sandbox Code Playgroud)
如果寿命view是显而易见的,那么你可以叫PyMem_Free上ptr你一直在做。