Fortran程序中的堆栈溢出

Fortran程序中的堆栈溢出,fortran,stack-overflow,Fortran,Stack Overflow,我的简单Fortran程序有问题。我使用的是Fortran 77,使用的是Compaq Visual Fortran。程序结构必须采用主程序和子程序的形式,因为它是与有限元法相关的大型程序的一部分 我的问题是我想分别为NHELE和NVELE设置值10000和10000,但是当我运行代码时,程序停止并给出以下错误: forrt1: server <170>: program Exception - stack overflow 谢谢。该编译器是否有将数组放入堆的选项 您可以尝试其他编

我的简单Fortran程序有问题。我使用的是Fortran 77,使用的是Compaq Visual Fortran。程序结构必须采用主程序和子程序的形式,因为它是与有限元法相关的大型程序的一部分

我的问题是我想分别为
NHELE
NVELE
设置值10000和10000,但是当我运行代码时,程序停止并给出以下错误:

forrt1: server <170>: program Exception - stack overflow

谢谢。

该编译器是否有将数组放入堆的选项


您可以尝试其他编译器,例如仍然受支持的编译器。Fortran 95编译器将编译Fortran 77。有很多选择,包括开源。Compaq Visual Fortran的继任者Intel Visual Fortran在Windows&Mac OS X上具有堆选项,用于在堆上放置自动和临时阵列。

更新

这是你真正的问题。您的
NM
数组被
NVNODE
行声明为
NHNODE
单元格的二维数组。如果是10000乘10000,那么除了您的程序正在使用的任何其他内存之外,您将需要超过381 MB的内存来单独分配此阵列。(相比之下,如果阵列为500 x 500,则同一阵列只需要大约1 MB的内存。)

问题是旧Fortran会直接在代码段或堆栈上分配所有数组。操作系统“堆”(大型对象的通用内存)的概念于1977年发明,但Fortran 77仍然没有任何利用它的结构。因此,每次调用子例程时,它都必须按下堆栈指针,以便为堆栈上381兆字节的空间腾出空间。这几乎肯定大于操作系统为堆栈段所允许的空间量,并且您正在溢出堆栈内存(因此会得到一个错误)

解决方案是从不同的位置分配内存。我知道在旧的Fortran中,可以使用
COMMON
块直接从代码段静态分配内存。您仍然无法动态分配更多,因此您的子例程无法重入,但如果您的子例程一次只被调用一次(看起来是这样),这可能是最好的解决方案

更好的解决方案是切换到Fortran 90或更高版本,并使用
ALLOCATE
关键字在堆上而不是堆栈上动态分配数组。然后,您可以分配尽可能大的内存块,但您不必担心堆栈溢出,因为内存将来自另一个地方


正如M.S.B.所建议的,您可以通过在编译器中更改它来修复此问题,但更好的解决方案是简单地修复代码

MELE实际上是一个比NM更大的数组:10000 x 10000 x 4 x 4,而不是10001 x 100001 x 4(假设有4个字节,Daniel也是如此)——1.49 GB而不是381 kB。MELE在您的主程序中声明,并且从您的测试来看是可以接受的,即使它更大。因此,要么添加NM将内存使用量推到了一个极限(这两个阵列的总容量为1.86 GB),要么声明中的差异很重要。MELE的大小在编译时已知,NM的大小仅在运行时已知,因此编译器可能会以不同的方式分配内存。实际上,在这个程序中,NM的大小是已知的,但在子例程中,维度作为参数接收,因此对于编译器来说,大小是未知的。如果更改此选项,编译器可能会更改为NM分配内存的方式,并且程序可能会运行。不要将NM的维度作为参数传递——将它们设置为常量。优雅的方法是创建一个包含三个参数语句的include文件,设置数组大小,然后根据需要包含该include文件。作为一个测试,快速而肮脏的做法是在子例程中重复相同的参数语句——但这样您就有了两次相同的信息,如果您进行了更改,则必须更改两次。在任何一种情况下,都必须从调用和子例程声明中的子例程参数中删除数组维度,或者使用不同的名称,因为子例程中的同一变量不能是参数和参数。如果不起作用,在主程序中声明NM,并将其作为参数传递给子例程

Re是公共块——维度需要在编译时已知,因此不能是子例程参数——同上。正如Daniel所解释的,将数组放到公共位置肯定会导致它不在堆栈上


这超出了语言标准——编译器如何提供内存是一个实现细节,“在引擎盖下”。因此,解决方案是部分猜测工作。编译器的手册或帮助可能有答案,例如,堆分配选项。

与数组大小相关的堆栈溢出是一个警告信号,表明它们被整体推送到调用堆栈上,而不是堆上。您是否尝试过使数组变量可分配?(我不确定这在F77中是否可行)

嗨,谢谢,我不知道它是否有这个选项!!:我不是专家。。。我正在考虑使用接口声明语句,但我不知道如何在这里使用它。如果你知道如何使用它。。。我将非常感谢,或者如果你有其他方法来解决这个问题,谢谢you@ghazooo:
接口
对您没有帮助,因为它是用于链接到单独编译的子例程的实现(通常由不同的编译器编译)。正如Daniel所写的,接口声明没有帮助——这只是描述子例程,这不会改变它。尝试在手册或帮助中搜索与堆分配相关的选项,或切换到当前支持的编译器。Daniel关于将大型数组放入公共块的另一个建议可能会奏效。@ghazoo,如果你是
PARAMETER(NHELE=508,NVELE=508)
PARAMETER(NHNODE=NHELE+1,NVNODE=NVELE+1)
PARAMETER(NTOTALELE=NHELE*NVELE)

DIMENSION MELE(NTOTALELE,4)

    CALL NIGTEE(NHELE,NVELE,NHNODE,NVNODE,NTOTALELE,MELE)

OPEN(UNIT=7,FILE='MeshNO For Rectangular.TXT',STATUS='UNKNOWN')
WRITE(7,500) ((MELE(I,J),J=1,4),I=1,NTOTALELE)
500 FORMAT(4I20)

    STOP
END

  SUBROUTINE NIGTEE(NHELE,NVELE,NHNODE,NVNODE,NTOTALELE,MELE)
DIMENSION NM(NVNODE,NHNODE),NODE(4)
DIMENSION MELE(NTOTALELE,4)

KK=0
DO 20 I=1,NVNODE
DO 20 J=1,NHNODE
KK=KK+1
NM(I,J)=KK
20  CONTINUE
  KK=0
DO 30 I=1,NVELE
DO 30 J=1,NHELE
NODE(1)=NM(I,J)
NODE(2)=NM(I,J+1)
NODE(3)=NM(I+1,J+1)
NODE(4)=NM(I+1,J)
KK=KK+1
DO 50 II=1,4
50  MELE(KK,II)=NODE(II)

30  CONTINUE
  RETURN
END