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

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.08.18 11:01:01