使用CFFI从Numpy数组为C++结构体数组分配内存时遇内存损坏
问题分析与解决方法
核心问题
- 类型不匹配导致数据错误:numpy默认的
shape元素是64位整数(int64),但C结构体中shape是32位int指针,直接memmove会把64位数据写入32位内存,造成数据截断(比如第二个维度的6被截断为0);同时numpy的float是64位双精度类型,与C的32位float类型不匹配,会引发内存读写异常。 - 内存管理隐患:C++中用
new分配的内存没有对应释放逻辑,长期运行会导致内存泄漏,当前崩溃的直接诱因是类型不匹配引发的内存损坏。
具体修复步骤
1. 修正Python端的类型匹配
修复shape的类型问题
将numpy的shape转换为32位整数数组,完全匹配C的int类型:
# 替换原shape复制代码 host_array_struct.shape = ffi.new(f"int[{numpy_array.ndim}]") # 将shape转为int32类型的numpy数组后复制 shape_int32 = np.array(numpy_array.shape, dtype=np.int32) ffi.memmove(host_array_struct.shape, ffi.cast("int*", ffi.from_buffer(shape_int32)), numpy_array.ndim * ffi.sizeof("int"))
修复数组的类型问题
如果C端需要32位单精度浮点数组,直接创建float32类型的numpy数组:
# 替换原数组创建代码 numpy_array = np.zeros((5,6), dtype=np.float32) host_array_struct.array = ffi.new(f"float[{host_array_struct.len}]") ffi.memmove(host_array_struct.array, ffi.cast("float*", ffi.from_buffer(numpy_array)), host_array_struct.len * ffi.sizeof("float"))
2. 添加内存释放逻辑
为避免内存泄漏,在C++端新增释放函数:
extern "C" void free_array_struct(struct array_struct* arr) { delete[] arr->shape; // 如果后续用new分配了array内存,也要加上delete[] arr->array; arr->shape = nullptr; arr->array = nullptr; }
然后在Python端声明并调用:
ffi.cdef("void free_array_struct(struct array_struct* arr);") # 使用完device_array_struct后调用释放 lib.free_array_struct(device_array_struct)
3. 验证修复效果
修复后C端的打印输出会恢复正常:
Printing device_array info: device_array->ndim = 2 device_array->shape = (5, 6, ) device_array->len = 30
同时不会出现内存损坏错误。
完整修复后的Python代码示例
import numpy as np from cffi import FFI ffi = FFI() ffi.cdef( """ struct array_struct { int ndim; int len; int* shape; float* array; }; """) ffi.cdef( """ void allocate( struct array_struct *host_array, struct array_struct *device_array ); void free_array_struct(struct array_struct* arr); """) lib = ffi.dlopen("./cupid/src/libAlg.so") # 创建float32类型的numpy数组 numpy_array = np.zeros((5,6), dtype=np.float32) host_array_struct = ffi.new("struct array_struct *") host_array_struct.ndim = numpy_array.ndim host_array_struct.len = numpy_array.size # 处理shape:转为int32类型 host_array_struct.shape = ffi.new(f"int[{numpy_array.ndim}]") shape_int32 = np.array(numpy_array.shape, dtype=np.int32) ffi.memmove(host_array_struct.shape, ffi.cast("int*", ffi.from_buffer(shape_int32)), numpy_array.ndim * ffi.sizeof("int")) # 处理array:直接用float32数组复制 host_array_struct.array = ffi.new(f"float[{host_array_struct.len}]") ffi.memmove(host_array_struct.array, ffi.cast("float*", ffi.from_buffer(numpy_array)), host_array_struct.len * ffi.sizeof("float")) device_array_struct = ffi.new("struct array_struct *") lib.allocate(host_array_struct, device_array_struct) # 使用完后释放内存 lib.free_array_struct(device_array_struct)
内容的提问来源于stack exchange,提问作者TheGitPuller
相关产品推荐
相关产品推荐

