2016-11-20 58 views
0

我寫了一個用Cython函數採用數字作爲參數列表/輸入memoryview並返回一個類型化Memoryview長度相同的:用Cython - 任意長度的返回類型化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

請參閱https://cython.readthedocs.io/en/stable/src/userguide/memoryviews.html#cython-arrays和'.callback_free_data' – DavidW

回答

0

類型化的memoryview就像名字暗示着一個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正在查看的內存不再存在。所以你是正確的,內存是正確釋放的。但是現在,內存視圖不再適合你。