You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

使用CFFI从Numpy数组为C++结构体数组分配内存时遇内存损坏

问题分析与解决方法

核心问题

  1. 类型不匹配导致数据错误:numpy默认的shape元素是64位整数(int64),但C结构体中shape是32位int指针,直接memmove会把64位数据写入32位内存,造成数据截断(比如第二个维度的6被截断为0);同时numpy的float是64位双精度类型,与C的32位float类型不匹配,会引发内存读写异常。
  2. 内存管理隐患: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

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.07.31 12:25:31