【发布时间】:2018-08-23 12:40:24
【问题描述】:
非常简单的设置,在 linux (red hat) 上使用 gfortran 4.8.5:
如果我的实数数组(在派生类型内)的大小 > 2,000,000,我会收到段错误。这似乎是一个标准的堆栈/堆问题,因为如果我检查
ulimit,我的堆栈大小是 8mb。如果数组NOT在派生类型中,则没有问题
请注意,正如@francescalus 猜测的那样,删除初始值
= 0.0可以消除问题
编辑添加:请注意,我已经发布了一个后续问题Segmentation fault related to component of derived type,它代表了一个更现实的用例,并进一步缩小了似乎发生这种情况的条件。
program main
call sub1 ! seg fault if col size > 2,100,000
call sub2 ! works fine at col size = 100,000,000
end program main
subroutine sub1
type table
real :: col(2100000) = 0.0 ! works if "= 0.0" removed
end type table
type(table) :: table1
table1%col = 1.0
end subroutine sub1
subroutine sub2
real :: col(100000000) = 0.0
col = 1.0
end subroutine sub2
这里有一些明显的问题:
这是预期行为,还是已在较新版本的 gfortran 中修复的某些错误?
我是在遵循标准的 fortran 操作程序,还是做错了什么?
建议的避免这种情况的方法是什么(请假设我近期无法更新到较新版本的 gfortran)?我几乎肯定会使用可分配数组组件来解决这个问题,但这可能不是一个理想的通用解决方案,我想知道我在这里拥有的所有好的选择。
特别是,初始化派生类型的组件是不好的做法吗?
【问题讨论】:
-
你有什么特别想要的“修复”吗?也就是说,您是否愿意更改代码(不仅仅是可分配组件),或者只是编译器标志等?
-
我不是 gfortran 方面的专家,所以不能给你答案。但是,问题似乎在于派生类型的默认初始化:如果可能,删除它可能就足够了。 [请注意,组件的默认初始化和
sub2中的显式初始化确实意味着不同的东西。] -
@HighPerformanceMark 我试图制作一个 MCVE stackoverflow.com/help/mcve 我当然可以让它更长,更“有用”。我使用的实际代码将子例程放在一个模块中,但有同样的问题。我不确定是应该像这里那样做还是使用“包含”来模拟实际的模块化。使用 2 个没有参数的“无意义”子程序仅仅是为了将它们完全分开并且没有 2 个程序。
sub2仅用于比较,本身并不特别感兴趣。 -
@JohnE,变量和数组的静态初始化通常会放在堆栈上。 gfortran 有一个 -fstack-array 选项。它可能有它的否定,即-fno-stack-array,它可能会阻止使用堆栈。这可能会增加代码大小和运行时间。最后,这不是 gfortran 问题。这是 Fortran 程序暴露的环境的问题。使用不同的编译器也可能会达到堆栈限制。
-
请注意,gfortran 开发人员@Steve 在上面的评论中讨论的编译器选项实际上是
-fstack-arrays和(手册页中没有)-fno-stack-arrays,在这两种情况下都是复数arrays。不幸的是,对于 gfortran 7.3.0 和 8.2.0,-fno-stack-arrays似乎无法解决这里的问题。