目前我正在为Fortran 95中的数值模拟代码工作。我的平台是WIndows,我利用了英特尔Fortran编译器的MSVC环境。 该代码与该领域中的许多代码一样,创建了一个待解析的方程组。在数值上,这发生了存储方阵和已知值的矢量。现在,为了优化存储器,矩阵以方便的形式存储,如压缩的稀疏行格式(CSR)或类似的,因此不存储零值。
鉴于这个简短的介绍,这里有我的怀疑。 因为在编译时我不知道我的数组的维度,我只是将它们声明为:
REAL, DIMENSION(:), ALLOCATABLE :: myArray
一旦我检索到这样一个向量的维度,我就会调用
ALLOCATE(myArray(N)) where N is the number of elements that I want to allocate
现在,用值填充它,占用的空间增加。 Fortran数组的结构,无论是一维向量还是多维数组,都是按列顺序填充一个等于值的空间。这就是说,如果我们有一个尺寸为1000x1000的二维数组,它将被存储在按列号排序的1M“连续框”中(首先存储第一列,然后存储第二列,依此类推......)。 p>
如果这是真的,那么数据的结构是一样的,对于特定值的访问时间是多维和1D向量之间的唯一区别吗?
然后命令RESHAPE
只改变程序“看到”数组的方式吗?
我需要的数组是在每个子例程/函数共享的模块中定义的。特别是,子程序分配并填充它。回到主程序,没有问题,因为我向用户显示了一些有关它的统计信息。让我们说,我们分配了400M REAL * 4值,大约1.5GB的已用内存。
然而,一旦我进入另一个子程序,程序就会停止说forrtl: severe(170): Program Exception - Stack Overflow
。我的内存耗尽了。但是如果矩阵已经分配并且我没有分配更多东西怎么可能呢?请注意:子例程使用相同的模块,因此已经声明了变量;我的RAM还有大约1.3GB的可用空间;停止位于子程序的第一行。
子程序(以及功能)是否使数据加倍?在这种情况下,我认为Fortran会传递变量的地址,避免复制并直接处理值。
最后,正如你们许多人一样,我喜欢在C ++中使用STD库函数,比如vector :: push_back等等。在Fortran中,没有如此美丽的例程,但仍然存在一些非常有用的功能。使用WHERE
或COUNT
或MERGE
屏蔽数组可以帮助您有效地处理某些操作。
提前感谢您的耐心等待!所有的建议都非常受欢迎!!
答案 0 :(得分:2)
评论空间有限,所以我将此作为答案发布。显然你的堆栈空间已经用完了,而不是内存不足。 Windows上主线程的堆栈大小在链接时固定(默认值为1 MiB),任何较大的堆栈分配都可能导致堆栈溢出。这可能是因为很多原因,但主要是:
ALLOCATABLE
数组); myArray(1:10:2)
,并且您没有该子例程的显式接口。在这种情况下,编译器会对传递的数据进行临时最可能的堆栈副本,这可能会耗尽堆栈空间并触发异常。我猜第一点是与你的情况相关的那一点,因为当你输入子程序时可能会发生异常(可能在序言中,所有局部变量的堆栈空间都被保留)。您可以指示英特尔Fortran在项目设置中启用堆数组并查看它是否有帮助(不确定Windows版本是否允许堆数组是默认值)。
如果没有显示一行代码,就很难猜出问题的根源是什么并解决它。