用Fortran写程序经常会分配一些数组使用,但究竟能分配多大的数组,这受编译环境、电脑可用内存容量、数组分配方式的影响,做了些测试,分享一下。
操作系统:Win8.1 64位
内存:8G(由于集成显卡需要使用一部分内存,实际可用内存7.7G)
编译器:Intel(R) Visual Fortran Composer XE 2013 SP1 Update 3(Visual Fortran Compiler XE 14.0.3.202)+Visual Studio 2010
其它:整型、实型均采用系统默认设置(整型4字节,实型8字节)
一、固定数组分配方式
早期的Fortran程序多使用parameter来定义一个静态变量,然后用此静态变量来进行数组大小定义,这里称此为固定数组分配方式。典型代码如下,本次测试也使用以下代码:
!===========分割线=================
program TestArray
implicit none
integer,parameter::n=489000000 !静态数组
real a(n)
a=0.0
end program TestArray
!===========分割线=================
在这个代码中只需要修改n的数值,就可以更改数组大小。测试时操作系统和其它应用程序已经占用电脑3.6G内存,系统可用内存为7.7-3.6=4.1G。测试了Win32和Win64两种编译器得到的程序,得到如下结果
Win32位:最大数组元素为48.9千万个(忽略百万以下数据,下同)
Win64位:最大数组元素为49.6千万个(当为53.6千万个时也能编译,但无法执行程序)
因此,固定数组分配方式下,32位和64位程序似乎差异不大。找了些资料大概看了一下,说是Fortran对单个数组的分配空间不能超过1G,没有再进一步核实。但若果真如此,那也说明32位和64位没有影响了,因为二者在1G内存空间内寻址都是没有问题的。此种分配方式下,电脑内存没有用完。
二、动态数组分配方式
自Fortran90以来,利用allocatable使用动态数组是非常方便的,因此,再测试一下此种方式分配数组。采用的测试代码如下:
!===========分割线=================
program TestArray
implicit none
integer n,i,k
real,allocatable:: a(:)
n=100000000 !1亿
k=10000000 !1千万
do i=1,50
n=n+k*5 !每次增加5千万
allocate(a(n))
a=0.0
write(*,*)n/k,'千万数据分配成功'
deallocate(a)
end do
end program TestArray
!===========分割线=================
此代码利用一个循环结构,以10千万数组元素为基数,每次增加5千万数组元素,直到内存不足造成程序退出。
(一)Win32位编译执行结果
从图中看出,系统可用内存7.7-3.6=4.1G,直到程序出错退出,内存都没有使用完
Win32位下只分配了40千万个元素就提示虚拟内存不足了,这与固定数组分配方式差不了多少
(二)Win64位编译执行结果
系统可用内存仍然为4.1G,动态数据分配时,随着数组元素增多,内存逐渐增大
在成功分配100千万(10亿)个元素后,再执行一次105千万数组元素分配时提示内存不足。
下面关闭一些应用程序,提高系统可用内存,使可用内存达到7.7-3.1=4.6G
随着数组元素增加,内存使用也在提高
最终110千万(11亿)数组元素成功分配,这是因为系统可用内存增加增加了0.5G。
因此,动态内存分配方式下,在32位模式下,数组的最大元素与固定数组分配差异不大。但在64位模式下,可分配数组的大小远大于固定数组分配方式,其最大数组元素数与系统可用内存有关,可用内存越大,可分配的数组就越大。
三、结论
固定数组定义方式,往往不知道后面需要多大的数组,为了保险期间,就会定义尽可能大的数组,从而造成内存浪费。而在需要更大的数组时,固定数组方式又显得无能为力,定义不出超过4.8亿元素的数组。因此,在进行数组定义时,尽可能的使用allocatable进行动态数组定义,这样可以更合理有效地使用内存。另外,当若需要超大型数组定义时,除了需要系统提供更大的内存外,使用64位编译器编译程序也是必须的。
说明:本测试没有使用硬盘进行虚拟内存,实际实用中若需要较大内存,但系统硬件内存又不够,也可以通过虚拟硬盘空间为内存的方式增加系统可用内存。