fortran - 数组的分段错误,但仅限于派生类型的组件
问题描述
非常简单的设置,在 linux (red hat) 上使用 gfortran 4.8.5:
如果我的实数数组(在派生类型内)的大小> 2,000,000,我会收到段错误。这似乎是一个标准的堆栈/堆问题,因为如果我使用
ulimit
.如果数组不在派生类型内,则没有问题
请注意,正如@francescalus 猜测的那样,删除初始值
= 0.0
可以消除问题
编辑添加:请注意,我已经发布了与派生类型组件相关的后续问题分段错误,它代表了一个更现实的用例,并进一步缩小了似乎发生这种情况的条件。
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 的错误。
Gfortran 使用堆栈来存储自动数组和其他初始化数据。当一个这样的数组很小时代码不会产生问题,但是当数组的大小增加时会出现段错误,一个可能的原因是堆栈不足。
在更新的 gfortran 版本中,这个问题似乎是相同的。我使用 gfortran 4.8.4、4.9.3、5.5.0、6.4.0、7.3.0 和 8.2.0 编译并运行了您的程序。在所有情况下,我都获得了默认堆栈大小的分段错误,但是当堆栈大小略微增加时没有错误。
$ ./sfa
Segmentation fault
$ ulimit -s
8192
$ ulimit -s 8256
$ ./sfa && echo "DONE"
DONE
您的问题可以通过运行解决
$ ulimit -s unlimited
在执行你的二进制文件之前。我不知道这样做有什么特别的惩罚,但是更了解内存管理细节的程序员,比如编译器开发人员,可能会不这么认为。
初始化派生类型的组件并不是一个坏习惯,但是正如您所看到的,如果组件是一个大数组,它可能会在堆栈中产生问题 - 无论是由于组件本身的存储,还是由于内存的存储在任务的 RHS 上工作。如果组件是可分配的并在子例程中分配,则数组存储在堆中而不是堆栈中,通常可以避免这个问题。在这种情况下,它可能实际上是在子例程中而不是在编译时动态设置数组的值。它可能不那么优雅,但我认为它是值得的,因为它是代码开发工作的典型示例,可以在执行二进制文件时防止可避免的与环境相关的错误。
您上面的代码符合标准。正如评论中所解释的,缺少子例程的显式接口不是好的做法,但对于这些简单的子例程,这并不违反规则。
一些编译器具有允许您更改某些对象在内存中的分配位置的标志。虽然它可以解决特定问题,但标志取决于编译器,并且在比较不同编译器时通常不等效。根据我的经验,通过 allocatables 使用动态内存是一种更强大的解决方案。
最后需要注意的是,如果你使用的是 OpenMP,上面的 ulimit 命令只会影响主线程——你需要通过环境变量来设置其他每个线程的堆栈大小,OMP_STACKSIZE
不能unlimited
。请记住,非主线程耗尽堆栈是一个更难以诊断的问题,因为二进制文件可能会在没有适当的分段错误错误的情况下停止。
推荐阅读
- javascript - Chess.js 交换回合
- java - 使用 axios POST 请求将 JSON 数据作为 multipart/form-data 发送
- python - 我有一个问题要在 sellenium(python) 中选择 xpath
- json - SQL Server - 使用 T-SQL 的 API 请求
- python - 是否可以在一个循环中同时运行多个异步函数?Python + 硒
- snowflake-cloud-data-platform - 在将数据插入表时使用变量 - 雪花过程
- flutter - 如何在小部件上连续点击一次并在小部件像钢琴一样触摸钢琴键时执行一些操作?
- python - python仪表板滑块格式化返回值
- hive - 试图从 Hive insert into 语句中找出返回码 2
- github - Azure 自托管代理管道上的 Git