gfortran带-fopenmp编译调用Intel MKL的Fortran DGEMM程序出现段错误问题
DGEMM程序加
-fopenmp后段错误原因排查 核心结论
你遇到的段错误,确实和Fortran 77风格的静态数组栈分配机制直接相关。
具体触发逻辑
- 先计算代码里几个静态数组的总内存开销(双精度浮点数单元素占8字节):
A(2000,200):20002008 = 3.2MBB(200,1000):20010008 = 1.6MBC(2000,1000):200010008 = 16MBAT(200,2000):20020008 = 3.2MB
四个数组累计占用约24MB内存。
- 不带
-fopenmp编译时,gfortran默认会把这类无显式分配属性的模块级/主程序静态数组,放到程序的全局静态存储区,不占用进程栈空间,因此哪怕Linux默认栈上限仅为8MB,程序也能正常运行。 - 加上
-fopenmp编译参数后,gfortran的内存分配规则会发生关键变更:所有不带save、allocatable属性的非可分配局部静态数组,会被编译到栈上分配,不再放入全局静态存储区。
此时哪怕你在.bashrc里配置OMP_STACKSIZE=6000m也完全无效:这个环境变量仅控制OpenMP并行工作线程的栈大小,而编译期生成的栈内存请求是主程序入口的栈空间,大小由系统shell的ulimit栈配置决定,24MB的栈请求已经远超默认8MB的栈上限,程序启动时直接触发段错误,根本执行不到读取OpenMP环境变量的逻辑。
可分配数组修复的原理
将静态数组改为allocatable可分配数组后,内存会在运行时通过堆分配接口申请,存放位置属于进程堆区,完全不占用任何线程的栈空间。堆内存的大小仅受系统可用物理内存、交换分区容量限制,不受单线程栈上限约束,自然就消除了栈溢出类的段错误。
内容的提问来源于stack exchange,提问作者AlphaF20
相关产品推荐
相关产品推荐

