当 Fortran 生成大型内部临时数组时,如何避免堆栈溢出?
Posted
技术标签:
【中文标题】当 Fortran 生成大型内部临时数组时,如何避免堆栈溢出?【英文标题】:How can I avoid a stack overflow when Fortran produces a large, internal, temporary array? 【发布时间】:2015-08-10 03:27:09 【问题描述】:我有一些 Fortran 代码调用 RESHAPE
对矩阵进行重新排序,这样我现在要循环的维度成为第一个可变维度(Fortran 中的列优先顺序)。
这与 C/Fortran 互操作性无关。
现在矩阵相当大,当我调用RESHAPE
函数时,我得到一个段错误,我非常确信这是堆栈溢出。我知道这一点,因为我可以使用 -heap-arrays
在 ifort 中编译我的代码,问题就消失了。
我不想修改堆栈大小。此代码需要可移植到任何计算机上,而用户不必担心堆栈大小。
有没有办法让RESHAPE
函数的这个调用使用堆而不是堆栈来使用它的内部内存。
在最坏的情况下,我将不得不为此实例“滚动我自己的”RESHAPE
函数,但我希望有更好的方法。
【问题讨论】:
重塑是否比修改循环来处理数组的结构更便宜? (例如,真的有必要重塑吗?) 我相信是的。我需要的是循环切片。要么我使用reshape
进行一些预处理,以使这些切片预先在内存中连续,要么在我请求不连续的内存时产生大量临时数组。
编译器创建一个临时的。如果没有编译器选项,您不能可移植地指示它把它放在堆上。我会手动进行转置。
为什么编译器不能只检查请求的临时数组的大小,将其与堆栈大小进行比较,并相应地使用堆(提示提示 Intel)?
英特尔已经提供了解决方案;它是-heap-arrays。这个选项也有一个尺寸截止值,这正是您的建议。
【参考方案1】:
Fortran 标准根本没有谈到堆栈和堆,这是一个实现细节。在内存的哪个部分放置东西以及是否有任何限制是实现定义的。
因此,不可能从 Fortran 代码本身控制堆栈或堆的行为。如果您想指定这个并且编译器选项用于那个,则必须通过其他方式指示编译器。 Intel Fortran 默认使用堆栈并具有 -heap-arrays n
选项(n 是限制,以 kB 为单位),gfortran 略有不同并具有相反的 -fstack-arrays
选项(包含在 -Ofast
中,但可以禁用)。
这对各种临时数组和自动数组都有效。
【讨论】:
所以解决方案是查找堆栈大小并设置-heap-arrays n
以合理猜测需要多大的数组才能进入堆。问题是,当将编译后的代码发送出去时,如果用户没有相同的堆栈大小,那么这个方法仍然会失败。因此,唯一可靠的方法是使用-heap-arrays
,它将所有内容都放在堆上,而您将失去堆栈的优势。
你可以很安全地放几个 kB,否则你必须避免任何递归,因为它会增加堆栈。
@EMiller 您应该检查一下,但 iirc ifort 实际上并不尊重-heap-arrays
的参数,而是将所有内容都放在堆上。我使用的最后一个版本是 14,所以从那时起可能已经改变了。以上是关于当 Fortran 生成大型内部临时数组时,如何避免堆栈溢出?的主要内容,如果未能解决你的问题,请参考以下文章