Fortran内存管理和子例程/函数

时间:2013-01-25 15:10:34

标签: arrays function memory-management fortran subroutine

目前我正在为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中,没有如此美丽的例程,但仍然存在一些非常有用的功能。使用WHERECOUNTMERGE屏蔽数组可以帮助您有效地处理某些操作。

  • 但是,当我的矩阵大于1M条目时,它们的速度很慢。在这种情况下,即使顺序搜索和替换也比创建掩码或使用where更快。怎么可能呢?他们不是多线程的吗?

提前感谢您的耐心等待!所有的建议都非常受欢迎!!

1 个答案:

答案 0 :(得分:2)

评论空间有限,所以我将此作为答案发布。显然你的堆栈空间已经用完了,而不是内存不足。 Windows上主线程的堆栈大小在链接时固定(默认值为1 MiB),任何较大的堆栈分配都可能导致堆栈溢出。这可能是因为很多原因,但主要是:

  • 您调用的子例程使用大堆栈数组(例如非ALLOCATABLE数组);
  • 您将非连续数组子部分传递给子例程,例如: myArray(1:10:2),并且您没有该子例程的显式接口。在这种情况下,编译器会对传递的数据进行临时最可能的堆栈副本,这可能会耗尽堆栈空间并触发异常。

我猜第一点是与你的情况相关的那一点,因为当你输入子程序时可能会发生异常(可能在序言中,所有局部变量的堆栈空间都被保留)。您可以指示英特尔Fortran在项目设置中启用堆数组并查看它是否有帮助(不确定Windows版本是否允许堆数组是默认值)。

如果没有显示一行代码,就很难猜出问题的根源是什么并解决它。