当 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 生成大型内部临时数组时,如何避免堆栈溢出?的主要内容,如果未能解决你的问题,请参考以下文章

如何在 Fortran 程序中设置内部挂钟?

Fortran `forall` 或 `do concurrent` 中的临时变量

使用 fortran 将文件读入数组:跳过多个标题行

Fortran如何编写非零元素

Fortran:稀疏数组或列表

可以将 Fortran 数组保存为 .npy 格式吗?