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

为什么堆上创建的数组使用AVX指令执行GEMM时会触发段错误?

问题根因

你触发段错误的核心原因是AVX指令的对齐要求未满足:

  • 你使用的_mm256_load_pd、_mm256_store_pd均为对齐访问指令,要求操作的内存地址必须是32字节对齐,报错的汇编指令vmovapd就是对齐的256位浮点数传送指令,地址不对齐就会触发SIGSEGV。
  • 栈上分配的二维数组默认会被编译器对齐到32字节边界,符合AVX的要求,因此运行正常。
  • 你用普通new分配的堆内存默认仅保证8字节对齐(匹配double类型的对齐要求),无法满足32字节对齐要求,因此触发段错误。

是否需要改用一维数组?

非常推荐改用一维连续数组,原因有两点:

  1. 便于实现对齐分配,能完美满足AVX指令的对齐要求
  2. 你当前实现的二维指针数组是逐行分配的,行与行之间内存不连续,会严重降低cache命中率,GEMM的性能会远低于连续一维数组的实现,这也是所有主流BLAS库的标准实现方式。

解决方案

方案1(推荐):使用对齐分配的一维数组

使用平台提供的对齐内存分配接口申请32字节对齐的连续内存:

// 分配示例,C11/C++11及以上可用aligned_alloc
double* A = (double*)aligned_alloc(32, M * K * sizeof(double));
double* B = (double*)aligned_alloc(32, K * N * sizeof(double));
double* C = (double*)aligned_alloc(32, M * N * sizeof(double));

// 访问方式转换为一维下标
vec_2 = _mm256_load_pd(&B[j*K + k]);
vec_res = _mm256_load_pd(&C[i*N + k]);
// ... 运算逻辑不变

// 释放内存用free,不要用delete
free(A);
free(B);
free(C);

Windows平台可替换aligned_alloc为_aligned_malloc,释放用_aligned_free。

方案2(临时兼容):改用非对齐AVX指令

如果你暂时不想改内存分配逻辑,可以把_mm256_load_pd换成_mm256_loadu_pd,_mm256_store_pd换成_mm256_storeu_pd,这两个指令支持非对齐访问,但性能会比对齐访问低10%~30%,仅适合临时调试使用。

方案3(保留二维下标访问):连续块+行指针映射

如果你想保留A[i][j]的二维访问方式,可以先申请一整块对齐的连续内存,再给行指针赋值:

void Malloc2DAligned(int height, int width, double**& Mat, double*& data) {
    Mat = new double*[height];
    data = (double*)aligned_alloc(32, height * width * sizeof(double));
    for(int i=0; i<height; i++) {
        Mat[i] = data + i * width;
    }
}

// 释放时先释放data,再释放行指针数组
free(data);
delete[] Mat;

内容的提问来源于stack exchange,提问作者zjnyly

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.10.04 22:57:02