2016-11-20 13 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__ для освобождения памяти.

Есть ли способ управлять сборкой мусора памяти, который не предполагает создание классов 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

Типичное представление памяти, так как название подразумевает представление буфера памяти. Он не владеет этой частью памяти, но обеспечивает эффективный способ доступа к ней. Часть документации cython, на которую вы ссылаетесь, - это способ привязки лежащего в основе кучи c-массива к сборщику мусора python. Если вы хотите использовать c-распределение памяти, как вы здесь, вы должны взять на себя ответственность за это. Это потому, что вы сейчас работаете на c-уровне, а c ничего не делает для вас бесплатно. Ваша функция делает вид выделенной памяти, но отбрасывает указатель, который ссылается на него. Теперь эта память сидит вокруг, и ничего не берет на себя ответственность за ее освобождение.

Если вы не хотите попасть в мир c, я рекомендую вам прочитать ваши данные на массив numpy в python и передать этот массив функции 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 освобождается вместе с ним. Это альтернатива, потому что вы просили об этом, но я по-прежнему рекомендую использовать этот метод.

В вашей второй функции вы, кажется, выделяете память, создаете представление и затем снова освобождаете ее. Теперь память, которую эта память просматривает, больше не существует. Итак, вы правы, память освобождается правильно. Но теперь память больше не нужна для вас.

 Смежные вопросы

  • Нет связанных вопросов^_^