- html - 出于某种原因,IE8 对我的 Sass 文件中继承的 html5 CSS 不友好?
- JMeter 在响应断言中使用 span 标签的问题
- html - 在 :hover and :active? 上具有不同效果的 CSS 动画
- html - 相对于居中的 html 内容固定的 CSS 重复背景?
我已经在Fortran 90中编写了一个相当大的程序。它已经运行了一段时间了,但是今天我尝试将其提高一个档次并增加问题的大小(这是研究非标准的有限元求解器,如果那样的话)。可以帮助任何人...)现在,我收到“堆栈溢出”错误消息,程序自然终止,而没有提供任何有用的帮助。
该程序首先设置所有相关的数组和矩阵,然后完成此操作,并将与此相关的几行统计信息打印到日志文件中。即使出现了新的更大的问题,它也可以正常工作(尽管有点慢),但是随着“数字紧缩”的进行,它就失败了。
令我感到困惑的是,那时所有的东西都已经分配了(并且可以正常工作而没有错误)。我不能完全确定堆栈是什么(维基百科和此处的几个步骤没有做太多事情,因为我对计算机的“幕后工作”只有一个非常基本的了解)。
假设我有一些初始化为的数组:
INTEGER,DIMENSION(64) :: IA
REAL(8),DIMENSION(:,:),ALLOCATABLE :: AA, BB
ALLOCATE( AA(N1,N2) , BB(N1,N2) )
IA(1) = N1
IA(2) = N2
CALL ROUTINE_ONE(AA,BB,IA)
SUBROUTINE ROUTINE_ONE(AA,BB,IA)
IMPLICIT NONE
INTEGER,DIMENSION(64) :: IA
REAL(8),DIMENSION(IA(1),IA(2)) :: AA, BB
...
do lots of other stuff
...
END SUBROUTINE ROUTINE_ONE
forrtl: severe (170): Program Exception - stack overflow
winsig.c
的文件(不是我的文件,但可能是编译器的一部分?)中中断。它似乎是名为
sigreterror:
的例程的一部分,并且是已调用的默认情况,返回了文本
Invalid signal or error
。对此附加了一条注释行,奇怪地显示
/* should never happen, but compiler can't tell */
...?
systeminfo
提示符下的
cmd
,我有8GB的物理内存和近16GB的虚拟内存。据我了解,我所有数组和矩阵的总和不应超过100MB-约5.5M
integer(4)
和2.5M
real(8)
(在我看来,这应该只有约44MB,但公平地说,再添加50MB (用于开销)。
! Update continuum state
CALL UpdateContinuumState(iTask,iArray,posc,dof,dof_k,nodedof,elm,&
bmtrx,detjac,w,mtrlprops,demtrx,dt,stress,strain,effstrain,&
effstress,aa,fi,errmsg)
posc
,
bmtrx
和
aa
-其他所有数组至少要小一个数量级(如果不多)。
posc
是
INTEGER(4)
和
bmtrx
,而
aa
是
REAL(8)
SUBROUTINE UpdateContinuumState(iTask,iArray,posc,dof,dof_k,nodedof,elm,bmtrx,&
detjac,w,mtrlprops,demtrx,dt,stress,strain,effstrain,&
effstress,aa,fi,errmsg)
IMPLICIT NONE
!I/O
INTEGER(4) :: iTask, errmsg
INTEGER(4) :: iArray(64)
INTEGER(4),DIMENSION(iArray(15),iArray(15),iArray(5)) :: posc
INTEGER(4),DIMENSION(iArray(22),iArray(21)+1) :: nodedof
INTEGER(4),DIMENSION(iArray(29),iArray(3)+2) :: elm
REAL(8),DIMENSION(iArray(14)) :: dof, dof_k
REAL(8),DIMENSION(iArray(12)*iArray(17),iArray(15)*iArray(5)) :: bmtrx
REAL(8),DIMENSION(iArray(5)*iArray(17)) :: detjac
REAL(8),DIMENSION(iArray(17)) :: w
REAL(8),DIMENSION(iArray(23),iArray(19)) :: mtrlprops
REAL(8),DIMENSION(iArray(8),iArray(8),iArray(23)) :: demtrx
REAL(8) :: dt
REAL(8),DIMENSION(2,iArray(12)*iArray(17)*iArray(5)) :: stress
REAL(8),DIMENSION(iArray(12)*iArray(17)*iArray(5)) :: strain
REAL(8),DIMENSION(2,iArray(17)*iArray(5)) :: effstrain, effstress
REAL(8),DIMENSION(iArray(25)) :: aa
REAL(8),DIMENSION(iArray(14)) :: fi
!Locals
INTEGER(4) :: i, e, mtrl, i1, i2, j1, j2, k1, k2, dim, planetype, elmnodes, &
Nec, elmpnodes, Ndisp, Nstr, Ncomp, Ngpt, Ndofelm
INTEGER(4),DIMENSION(iArray(15)) :: doflist
REAL(8),DIMENSION(iArray(12)*iArray(17),iArray(15)) :: belm
REAL(8),DIMENSION(iArray(17)) :: jelm
REAL(8),DIMENSION(iArray(12)*iArray(17)*iArray(5)) :: dstrain
REAL(8),DIMENSION(iArray(12)*iArray(17)) :: s
REAL(8),DIMENSION(iArray(17)) :: ep, es, dep
REAL(8),DIMENSION(iArray(15),iArray(15)) :: kelm
REAL(8),DIMENSION(iArray(15)) :: felm
dim = iArray(1)
...
最佳答案
按照Steabert的要求,我将在这里的评论中总结一下对话,尽管M.S.B.的答案已经很贴切地解决了这个问题,但在这里,它看起来更为明显。
在技术编程中,过程通常具有较大的局部数组用于中间计算,这种情况经常发生。局部变量通常存储在堆栈中,通常(相当合理地)占整个系统内存的一小部分-通常约为10MB。当局部变量大小超过堆栈大小时,您会确切地看到此处描述的症状-在调用相关子例程之后但在其第一个可执行语句之前,发生堆栈溢出。
因此,当发生此问题时,最好的办法是找到相关的大型局部变量,然后决定要做什么。在这种情况下,至少变量belm和dstrain变得相当大。
找到变量后,您已经确认是问题所在,这里有一些选择。正如MSB指出的那样,如果可以使阵列更小,那是一种选择。另外,您可以增加堆栈大小;在linux下,这是通过ulimit -s [newsize]
完成的。但是,这实际上只是推迟了该问题,您必须在Windows机器上做一些不同的事情。
避免此问题的另一类方法不是将大数据放在堆栈上,而是放在内存的其余部分(“堆”)中。您可以通过为数组赋予save
属性(在C中为static
)来实现;这会将变量放在堆上,从而使值在调用之间保持不变。缺点是,这可能会改变子例程的行为,这意味着该子例程不能递归使用,并且同样是非线程安全的(如果您处于多个线程将同时进入例程的位置,则它们每个人都会看到本地变量的相同副本,并有可能覆盖彼此的结果)。好处是它很容易而且非常便携-它应该可以在任何地方使用。但是,这仅适用于固定大小的局部变量。如果临时数组的大小取决于输入,则无法执行此操作(因为不再需要保存单个变量;每次调用该过程时,大小可能都不同)。
有特定于编译器的选项,这些选项将所有数组(或所有大于某个给定大小的数组)放到堆而不是堆栈上。我知道的每个Fortran编译器都有一个选项。对于OPort中使用的ifort,在Linux中是-heap-arrays
,在Windows中是/heap-arrays
。对于gfortran,这实际上可能是默认设置。这有助于确保您知道发生了什么,但这意味着每个编译器都必须具有不同的要求,以确保您的代码能够正常工作。
最后,您可以使有问题的数组可分配。分配的内存在堆上;但是指向它们的变量在堆栈中,因此您可以从这两种方法中受益。而且,这是完全标准的fortran,因此完全可移植。缺点是需要更改代码。同样,分配过程可能要花费很短的时间。因此,如果您要调用无数次例行 session ,您可能会注意到这会稍微减慢速度。 (但是,这种可能的性能回归很容易修复;如果要使用相同大小的数组将其称为数十亿次,则可以有一个可选参数来传递预分配的本地数组,并使用该参数,以便您只能分配/取消分配一次)。
每次分配/分配看起来像:
SUBROUTINE UpdateContinuumState(iTask,iArray,posc,dof,dof_k,nodedof,elm,bmtrx,&
detjac,w,mtrlprops,demtrx,dt,stress,strain,effstrain,&
effstress,aa,fi,errmsg)
IMPLICIT NONE
!...arguments....
!Locals
!...
REAL(8),DIMENSION(:,:), allocatable :: belm
REAL(8),DIMENSION(:), allocatable :: dstrain
allocate(belm(iArray(12)*iArray(17),iArray(15))
allocate(dstrain(iArray(12)*iArray(17)*iArray(5))
!... work
deallocate(belm)
deallocate(dstrain)
SUBROUTINE UpdateContinuumState(iTask,iArray,posc,dof,dof_k,nodedof,elm,bmtrx,&
detjac,w,mtrlprops,demtrx,dt,stress,strain,effstrain,&
effstress,aa,fi,errmsg,workbelm,workdstrain)
IMPLICIT NONE
!...arguments....
real(8),dimension(:,:), optional, target :: workbelm
real(8),dimension(:), optional, target :: workdstrain
!Locals
!...
REAL(8),DIMENSION(:,:), pointer :: belm
REAL(8),DIMENSION(:), pointer :: dstrain
if (present(workbelm)) then
belm => workbelm
else
allocate(belm(iArray(12)*iArray(17),iArray(15))
endif
if (present(workdstrain)) then
dstrain => workdstrain
else
allocate(dstrain(iArray(12)*iArray(17)*iArray(5))
endif
!... work
if (.not.(present(workbelm))) deallocate(belm)
if (.not.(present(workdstrain))) deallocate(dstrain)
关于fortran - Fortran 90中的堆栈溢出,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/5795938/
是的,我知道..,这不是想象的...这是一个真正的 Fortran 问题。 以前的版本是指 Fortran 2003、95、90,甚至 77。 我所说的“向后兼容”是指可以轻松运行为 2008 年以前
我有一个程序,它的变量中有一个值。一旦确定了该值,我想调用另一个程序并使用该变量的值来确定在新程序中的位置。有人知道该怎么做吗? 最佳答案 如果您有 Fortran 2008 编译器,您将拥有标准子例
namelist 是一种有用的 fortran 结构,可以从文件中快速初始化变量。 namelist 有一个名称并包含一组具有已知类型的变量。这使得它类似于 type 结构。 通常情况下,给程序或子例
我正在遍历索引,我正在检查我是否不在第一个循环交互和另一个条件中。如果第一个条件是 .False.,我不想评估第二个条件。 do i = 1, n if ( i /= 1 .and. var(
Fortran 2003 具有用于数组连接的方括号语法,Intel fortran 编译器也支持它。我在这里为矩阵连接写了一个简单的代码: program matrix implicit none r
我正在尝试通过重载类型名称来制作自定义数据类型构造函数。但是,在进行调用时,将调用默认构造函数。我不明白我做错了什么。 这是有问题的代码片段。 module test type, pu
我的最终目标是在 Fortran 中有一个通用的映射函数,即一个接受任意类型 A 的数组和一个 A->B 类型的函数的函数,将此函数应用于给定数组的所有元素并返回一个B 类型的数组。我无法用数组实现它
我正在学习 Fortran,在使用格式编写时发现了一些奇怪的东西(我使用的是 Fortran onlinegdb) Program Hello real, dimension(3,2):: array
Fortran 中的INTERFACE 语句是否使其成为正式实现multiple dispatch 的编程语言? ? (我问是因为所链接的维基百科文章在其看似全面的支持相关范式的示例编程语言列表中并未
我可以使用 Fortran 95 编译器编译 Fortran 90 文件吗? Fortran 95 似乎有很多,但 Fortran 90 没有。 最佳答案 这个可以: NAGWare f95 Comp
嗨,我在 Fortran 中对二维离散化问题强加边界条件时遇到了麻烦。我的离散化网格是一个二维正方形,在 x,y 方向上从 -L 到 L。 我想强加这样的边界条件, 在 x=L 的边界线上,指定了函数
Fortran 是否有与 C assert 等效的标准函数/关键字? ? 我找不到 assert我在Fortran2003标准中提到过。我发现了一些如何使用预处理器的方法,但是在这个 answer建议
我有一系列的作业,使用“;”将它们分配给同一个ike。分开statemnts,但我收到此错误: 1.0;磅(1,9) 1个 错误:(1)处无法分类的陈述 在文件LJ.F90:223中 如果每个语句都在
我正在使用 gfortran -std=f2008。我有一个函数,它返回一个包含可分配数组的派生类型。该函数在返回之前调用allocate()。似乎在分配数组的函数返回之后,数组会自动释放一段时间,并
我制作了这个小型测试程序来“证明”在编译之前(或者如果你让它们可分配),你不能在不指定它们的大小的情况下使用向量。我的观点失败了。我期待本地向量“num”会失败。程序在执行程序之前无法知道它的大小。大
出于优化原因,Fortran 强制子例程或函数的虚拟参数不是别名,即它们不指向相同的内存位置。 我想知道相同的约束是否适用于函数的返回值。 换句话说,对于给定的 myfunc 函数: function
我已经在Fortran 90中编写了一个相当大的程序。它已经运行了一段时间了,但是今天我尝试将其提高一个档次并增加问题的大小(这是研究非标准的有限元求解器,如果那样的话)。可以帮助任何人...)现在,
在 C 和 C++ 中,有许多操作会导致未定义的行为,即允许编译器做任何它想做的事情的情况。 Examples包括在释放变量后使用它,释放变量两次和取消引用空指针。 Fortran 是否也有未定义的行
通常我使用fortran进行数值分析,然后使用matlab、R和python进行后期和前期工作。 我发现 matlab、R 和 python 在终端中提供了命令提示符,以便您可以运行脚本以及从命令行立
在 Fortran 中将变量设置为 +Infinity 的最安全方法是什么?目前我正在使用: program test implicit none print *,infinity() con
我是一名优秀的程序员,十分优秀!