缓冲区过大时MPI程序出现segmentation fault错误的原因与解决
问题根因
你遇到的是典型的栈缓冲区溢出问题:
- 代码中定义的
float data[BUFFER_SIZE]和float base_output[BUFFER_SIZE]是分配在函数栈空间的局部变量,float类型占4字节,当BUFFER_SIZE=1024*1024时,单个数组大小为4MB,两个数组总大小达到8MB。 - macOS系统默认的用户进程栈大小上限恰好是8MB,当数组总大小超过栈容量时,就会触发非法内存访问,抛出
Segmentation fault: 11段错误。 - BUFFER_SIZE较小时数组总大小未超过栈上限,因此可以正常运行。
注意:该问题和MPI框架本身无关,属于C语言栈内存分配的通用问题,非MPI程序定义大局部数组时也会触发相同错误。
解决方法
方法1:将大数组改为静态全局变量
全局变量/静态变量分配在进程堆区而非栈区,不受栈大小限制,只需把数组定义移到main函数外部即可:
#include <mpi.h> #include <stdio.h> #include <stdlib.h> #include <sys/time.h> #define BUFFER_SIZE (1024 * 1024) // 移到函数外成为全局变量,分配在堆区 float data[BUFFER_SIZE]; float base_output[BUFFER_SIZE]; int main(int argc, char* argv[]) { printf("Buffer size is %d\n", BUFFER_SIZE); printf("Data pointer is %p\n", data); printf("Output pointer is %p\n", base_output); MPI_Init(&argc, &argv); MPI_Finalize(); return 0; }
方法2:动态申请内存
用malloc/free在堆上主动申请和释放内存,灵活性更高,也符合C语言大内存申请的通用规范:
int main(int argc, char* argv[]) { float *data = malloc(BUFFER_SIZE * sizeof(float)); float *base_output = malloc(BUFFER_SIZE * sizeof(float)); // 正常使用数组的逻辑 printf("Buffer size is %d\n", BUFFER_SIZE); printf("Data pointer is %p\n", data); printf("Output pointer is %p\n", base_output); // 程序退出前释放内存 free(base_output); free(data); MPI_Init(&argc, &argv); MPI_Finalize(); return 0; }
方法3:临时调整栈大小(不推荐)
可以在运行程序前通过ulimit命令临时调高栈大小上限,比如调整为16MB:
ulimit -s 16384 mpiexec -n 4 ./test
该调整仅在当前终端会话生效,且不同系统默认栈大小差异较大,兼容性差,不建议生产环境使用。
内容的提问来源于stack exchange,提问作者ChromatinRemodeling
相关产品推荐
相关产品推荐

