Python调用接收Numpy矩阵的C函数时malloc内存分配报错排查
在MacOS 11.6.1环境下,实现接收两个Numpy数组矩阵、返回新矩阵的C函数时,运行出现malloc错误:
Python(53609,0x111c84e00) malloc: can't allocate region
:*** mach_vm_map(size=5626830804037632, flags: 100) failed (error code=3)
Python(53609,0x111c84e00) malloc: *** set a breakpoint in malloc_error_break to debug
附相关代码:
C文件 f_2_mat_in.c
#include <stdlib.h> #include <stdio.h> #include <math.h> double *f_2_mat_in( const double *matrix_one, size_t n, size_t m, const double *matrix_two, size_t u, size_t v ) { double *matrix_out = malloc(sizeof *matrix_out * n * m); for (size_t i = 0; i < n; i++){ for (size_t j = 0; j < m; j++){ printf("%f ", matrix_one[i * m + j]); matrix_out[i * m + j] = matrix_one[i * m + j]; printf("--\n"); } } for (size_t i = 0; i < u; i++){ for (size_t j = 0; j < v; j++){ printf("%f ", matrix_two[u * v + j]); printf("--\n"); } } printf("\n"); return matrix_out; }
Python脚本 main.py
from ctypes import c_void_p, c_double, c_size_t, c_int, cdll, POINTER from numpy.ctypeslib import ndpointer import pdb import numpy as np c_double_p1 = POINTER(c_double) c_double_p2 = POINTER(c_double) n = 5 m = 4 kernel_size = 3 u = 3 v = 6 matrix_one = np.random.randn(n, m).astype(c_double) matrix_one[0][1] = np.nan lib = cdll.LoadLibrary("f_2_mat_in.so") f_2_mat_in = lib.f_2_mat_in f_2_mat_in.argtypes = c_int, c_double_p1, c_size_t, c_size_t, c_double_p2, c_size_t, c_size_t f_2_mat_in.restype = ndpointer( dtype=c_double, shape=(n,m), flags='C') f_2_mat_in.restype = ndpointer( dtype=c_double, shape=(u,v), flags='C') matrix_out = f_2_mat_in( c_int(kernel_size), matrix_one.ctypes.data_as(c_double_p1), c_size_t(n), c_size_t(m), matrix_one.ctypes.data_as(c_double_p2), c_size_t(u), c_size_t(v)) print("matrix_one:", matrix_one) print("matrix_two:", matrix_two) print("matrix_out:", matrix_out) print("matrix_one.shape:", matrix_one.shape) print("matrix_two.shape:", matrix_two.shape) print("matrix_out.shape:", matrix_out.shape) print("in == out", matrix_one == matrix_out) pdb.set_trace()
编译脚本
a=f_2_mat_in cc -fPIC -shared -o $a.so $a.c && python main.py
1. 参数顺序完全错位(核心错误)
C函数定义的参数顺序是:matrix_one → n → m → matrix_two → u → v,但Python的argtypes却把额外的kernel_size放在第一个位置,且C函数根本没有这个参数。这直接导致后续的尺寸参数n、m被错误赋值为随机大数值,计算malloc内存时得到天文数字(即错误中的5626830804037632),触发分配失败。
修正:
如果不需要kernel_size参数,直接删除Python中对应的传入项和argtypes里的c_int:
# 修改argtypes,移除开头的c_int f_2_mat_in.argtypes = [c_double_p1, c_size_t, c_size_t, c_double_p2, c_size_t, c_size_t] # 调用时去掉kernel_size参数 matrix_out = f_2_mat_in( matrix_one.ctypes.data_as(c_double_p1), c_size_t(n), c_size_t(m), matrix_one.ctypes.data_as(c_double_p2), c_size_t(u), c_size_t(v))
2. C函数中matrix_two索引越界
C代码访问matrix_two时用了matrix_two[u * v + j],正确的二维数组索引应该是i * v + j,当前写法会直接越界访问内存,破坏堆结构,也可能引发malloc异常。
修正:
for (size_t i = 0; i < u; i++){ for (size_t j = 0; j < v; j++){ printf("%f ", matrix_two[i * v + j]); // 将u*v改为i*v printf("--\n"); } }
3. Python重复设置restype
连续两次给f_2_mat_in.restype赋值,第二次会覆盖第一次。根据C函数返回的n*m大小数组,保留对应定义即可:
f_2_mat_in.restype = ndpointer( dtype=c_double, shape=(n,m), flags='C')
4. Python未定义matrix_two变量
代码中打印matrix_two但未定义该变量,会触发NameError,补充定义:
matrix_two = np.random.randn(u, v).astype(c_double)
5. 内存泄漏风险
C函数用malloc分配的内存,Python不会自动释放,长期运行会导致内存泄漏。可通过libc手动释放:
from ctypes import cdll, c_void_p libc = cdll.LoadLibrary("libc.dylib") # MacOS系统libc libc.free.argtypes = [c_void_p] # 使用完matrix_out后释放内存 libc.free(matrix_out.ctypes.data)
内容的提问来源于stack exchange,提问作者ecjb

