在fortran 90中使用标准数组和派生类型时的内存使用量之间的差异

use*_*624 4 fortran90

我观察到有关派生数据类型的内存使用情况的奇怪行为.以下fortran90代码演示了此问题.

  module prec
  implicit none
  integer, parameter :: d_t = selected_real_kind(15,307)
  end module
  module typdef
  use prec
  implicit none
  type level_2
  real(kind=d_t), allocatable :: lev_3(:)
  end type
  type level_1
  type(level_2),allocatable :: lev_2(:,:)
  end type
  type array
  type(level_1),allocatable :: lev_1(:,:)
  end type
  end module
  program mem_test
  use prec
  use typdef
  implicit none
  integer :: n,i,j,k,l,m,egmax,niter,ncells,namom,nsmom
  real(kind=d_t),allocatable :: simple_array(:,:,:,:,:)
  type(array)                :: fancy_array
  real(kind=d_t)             :: it
  egmax=7
  niter=2
  ncells=3000000
  namom=1
  nsmom=1
  !
  !
  !  
  allocate( simple_array(egmax,niter,ncells,namom,nsmom) )
  !
  !
  !
  allocate( fancy_array%lev_1(egmax,niter))
  do i=1,niter
   do j=1,egmax
     allocate( fancy_array%lev_1(j,i)%lev_2(ncells,namom) )
   end do
 end do
 do i=1,niter
   do j=1,egmax
     do k=1,namom
       do l=1,ncells
         allocate( fancy_array%lev_1(j,i)%lev_2(l,k)%lev_3(nsmom) )
       end do
     end do 
   end do
 end do
 !
 do n=1,100000
 it=0.0_d_T
 do i=1,100000
  it=it+1.0_d_t
 end do
 end do
 ! 
 !
 deallocate(simple_array)
 deallocate(fancy_array%lev_1)
 end program
Run Code Online (Sandbox Code Playgroud)

我想将数据存储在多维数组中(例如,max*niter*ncell*namom*nsmom双精度数).我以两种不同的方式做到了这一点:

  1. 多维标准数组"simple_array(egmax,niter,...,)"
  2. 嵌套的派生数据结构"fancy_array",如我提供的代码片段中所定义.

我使用编译代码

    ifort -g -o  test.exe file.f90
Run Code Online (Sandbox Code Playgroud)

我在valgrind中运行它并比较了simple_array和fancy_array的内存消耗.simple_array按预期使用大约300Mb,而fancy_array使用3Gb(10倍),即使它存储相同数量的实数.因此,它也应该只消耗300Mb.

运行一个更简单的测试用例,其中派生类型只有一个深度,例如

     type level_1
        real(kind=d_t),allocatable :: subarray(:)
     end type
     type array
        type(level_1),allocatable :: lev_1(:)
     end type         
Run Code Online (Sandbox Code Playgroud)

正好消耗我期望的内存量.它不会消耗10倍的内存.有没有人观察到类似的行为或有任何线索为什么会发生这种情况?我唯一的想法是所描述的行为的原因是fancy_array分配了非连续的内存,并且fortran需要跟踪它,因此内存消耗的增加.我将不胜感激任何意见或类似意见.

谢谢你的帮助.

塞巴斯蒂安

Ian*_*anH 6

(可分配的组件是Fortran 2003的一项功能.)

Fortran处理器(包括Intel Fortran)实现可分配数组对象的典型方法是使用描述符 - 一种数据结构,其中包含内存中数组数据的位置以及数组每个维度的边界和跨度等信息,除其他事项.

对于x64平台上的英特尔Fortran,描述符占用一维可分配数组的72个字节.在派生类型的情况下,您有大约4200万个这样的数组 - 一个用于lev_3您存在的每个组件,另外一个用于父可分配组件的数字要小得多.72字节乘以4200万,大约3 GB.可能存在与底层内存分配器相关的进一步开销.

在同一平台上,排名为五的数组的描述符占用168个字节,并且只有一个内存分配

这两种方法的数据存储要求大致相同.

请注意,这两种方法提供的功能明显不同(因此开销的差异) - 在派生类型的情况下,您可以更改每个 lev_3组件的分配状态,边界和范围.在单个数组的情况下,你没有任何接近灵活性 - 如果分配该数组必须是矩形的.

(在Fortran 90中,组件在声明中的维度需要是常量表达式(在编译时固定).不使用描述符,两种方法的内存要求会收敛.)