0

我编写了一个 Cython 函数,该函数将数字的列表/类型化内存视图作为参数并返回相同长度的类型化内存视图:

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)错误消息。我意识到这是一个内存管理问题,但我找不到如何管理函数返回的类型化内存视图的内存的示例。我发现的唯一有用信息是关于内存分配的信息,它建议将生命周期与result_arrpython 对象联系起来,并使用一种__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

为什么这行得通,是否有更好的方法来管理内存?

4

1 回答 1

1

类型化的内存视图顾名思义就是内存缓冲区的视图。它不拥有那块内存,但提供了一种有效的访问方式。您所指的 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 对你不再有用了。

于 2016-11-21T11:15:50.850 回答