Cython:释放内存的内存视图



在Cython代码中,我可以分配一些内存并将其封装在内存视图中,例如:

cdef double* ptr
cdef double[::1] view
ptr = <double*> PyMem_Malloc(N*sizeof('double'))
view = <double[:N]> ptr

如果我现在使用PyMem_Free(ptr)释放内存,那么尝试访问像ptr[i]这样的元素会抛出一个错误,这是应该的。但是,我可以安全地尝试访问view[i](但它不会返回原始数据)。

我的问题是:只释放指针总是安全的吗?内存视图对象是否以某种方式通知内存被释放,或者我应该以某种方式手动删除该视图?此外,即使内存视图引用了内存,也能保证释放内存吗?

需要对C代码进行一些挖掘才能显示这一点,但是:

线CCD_ 4实际上产生一个CCD_。这与文档中详细描述的"Cython数组"类型相同,cimpportable与cython.view.array类型相同。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);

__pyx_t_2__pyx_t_3只是分别存储大小和格式的临时存储器)。如果我们查看__pyx_array_new内部,我们首先会看到数组的data成员被直接分配给作为__pyx_v_ptr 传递的值

__pyx_v_result->data = __pyx_v_buf;

(即,复制是而不是),其次是未设置callback_free_data旁注:cython.view.array的C代码实际上是由Cython代码生成的,所以如果你想进一步研究,它可能比生成的C.更容易读取


从本质上讲,内存视图包含一个cython.view.array,它有一个指向原始数据的指针,但没有设置callback_free_data。当内存视图失效时,将调用cython.view.array的析构函数。这清理了一些内部,但并没有释放它所指向的数据(因为它没有指示如何释放)。

因此,在调用PyMem_Free之后访问内存视图是不安全的。你似乎侥幸逃脱了惩罚。如果你不访问内存视图,那么内存视图保持现有是安全的

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

那就好了。类似于的功能

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

这将是一个坏主意,因为它传递回一个不指向任何内容的内存视图,并在其查看的数据被释放后访问view

您一定要确保在某个时刻调用PyMem_Free,否则会发生内存泄漏。如果view被传递,因此寿命很难跟踪,那么一种方法是手动创建一个设置了callback_free_datacython.view.array

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

如果view的寿命是显而易见的,那么您可以像以前一样在ptr上调用PyMem_Free

相关内容

  • 没有找到相关文章

最新更新