Cython数组跨函数访问时前四元素值随机变更问题求助
问题原因与解决方案
核心问题:内存被垃圾回收
你直接把局部numpy数组point_index_list的内存指针赋值给了类成员self.point_index_array,但point_index_list是__init__方法里的局部变量。当__init__执行完毕后,Python的垃圾回收器会回收这个数组占用的内存,后续访问self.point_index_array时,这块内存已经被重新使用或释放,所以出现了随机的错误值。
解决办法
有两种可行的修复方式:
1. 保留numpy数组的引用
把point_index_list设为类的cdef属性,让Python一直持有它的引用,避免内存被回收:
cdef class KdTree: cdef uint32_t* point_index_array cdef np.ndarray[uint32_t, ndim=1] _point_index_list # 新增类属性 def __cinit__(KdTree self): self.point_index_array = NULL def __init__(KdTree self, np.ndarray points not None, int num_of_leaf=16): point_index = np.arange(0, self.num_of_points, dtype=np.uint32) self._point_index_list = np.ascontiguousarray(point_index.ravel(), dtype=np.uint32) self.point_index_array = <uint32_t*>self._point_index_list.data # ... 其他初始化代码
2. 手动分配内存并复制数据
如果不需要保留原numpy数组,可以手动分配C级别的内存,把数组数据复制进去,这样不受Python垃圾回收影响:
from libc.stdlib cimport malloc, free from libc.string cimport memcpy cdef class KdTree: cdef uint32_t* point_index_array cdef size_t _index_array_size # 记录数组长度 def __cinit__(KdTree self): self.point_index_array = NULL self._index_array_size = 0 def __init__(KdTree self, np.ndarray points not None, int num_of_leaf=16): cdef np.ndarray[uint32_t, ndim=1] point_index_list point_index = np.arange(0, self.num_of_points, dtype=np.uint32) point_index_list = np.ascontiguousarray(point_index.ravel(), dtype=np.uint32) self._index_array_size = point_index_list.shape[0] # 分配内存 self.point_index_array = <uint32_t*>malloc(self._index_array_size * sizeof(uint32_t)) if self.point_index_array == NULL: raise MemoryError("无法分配内存") # 复制数据 memcpy(self.point_index_array, point_index_list.data, self._index_array_size * sizeof(uint32_t)) # ... 其他初始化代码 def __dealloc__(KdTree self): # 释放内存,避免泄漏 if self.point_index_array != NULL: free(self.point_index_array)
注意第二种方式需要在类的__dealloc__方法里手动释放内存,防止内存泄漏。
内容的提问来源于stack exchange,提问作者J S
相关产品推荐
相关产品推荐

