Fortran:普通数组与存储相同数据量的对象所需的RAM

geo*_*fas 7 arrays oop ram fortran

尝试使用动态内存分配以两种不同的方式存储一些数据,我注意到RAM要求的巨大差异,我无法解释.一些见解将不胜感激.

在以下示例中,目标是创建一个数据库,该数据库在多边形网格中存储连接到节点的边的ID.但是,问题的性质是无关紧要的.

案例1,使用"普通"数组:

program memorytest

implicit none

integer, dimension(:, :), allocatable :: node_edges
integer :: i

allocate(node_edges(10, 10000000)) ! 10000000 nodes with 10 edges each
node_edges(:, :) = 0

read *, i ! pause

deallocate(node_edges)

end program memorytest
Run Code Online (Sandbox Code Playgroud)

RAM需要:~395,500 K.

案例2,使用节点类型:

program memorytest

implicit none

type node
  integer, dimension(:), allocatable :: edges  
end type

type(node), dimension(:), allocatable :: nodes
integer :: i

allocate(nodes(10000000)) ! 10000000 nodes
do i = 1, 10000000
    allocate(nodes(i)%edges(10)) ! with 10 edges each
end do

do i = 1, 10000000
    nodes(i)%edges(:) = 0
end do

read *, i ! pause    

do i = 1, 10000000
    deallocate(nodes(i)%edges)
end do
deallocate(nodes)

end program memorytest
Run Code Online (Sandbox Code Playgroud)

RAM需要:~1,060,500 K.

为了进行比较,我尝试了C++中的等效方法.

案例1,使用"普通"数组:

#include "stdafx.h"
#include <iostream>

int main()
{
  int** node_edges;
  int i, j;

  node_edges = new int*[10000000]; // 10000000 nodes
  for(i = 0; i < 10000000; i++) node_edges[i] = new int[10]; // with 10 edges each

  for(i = 0; i < 10000000; i++)
    for(j = 0; j < 10; j++) node_edges[i][j] = 0;

  std::cin >> i; // pause

  for(i = 0; i < 10000000; i++) delete [] node_edges[i];
  delete [] node_edges;

    return 0;
}
Run Code Online (Sandbox Code Playgroud)

RAM需要:~510,000 K.

案例2,使用节点类:

#include "stdafx.h"
#include <iostream>

class node
{
  public:
    int* edges;
};

int main()
{
  node* nodes;
  int i, j;

  nodes = new node[10000000]; // 10000000 nodes
  for(i = 0; i < 10000000; i++) nodes[i].edges = new int[10]; // with 10 edges each

  for(i = 0; i < 10000000; i++)
    for(j = 0; j < 10; j++) nodes[i].edges[j] = 0;

  std::cin >> i; // pause

  for(i = 0; i < 10000000; i++) delete [] nodes[i].edges;
  delete [] nodes;

    return 0;
}
Run Code Online (Sandbox Code Playgroud)

RAM需要:~510,000 K.

使用的开发环境:英特尔Visual Fortran Studio XE 2013和MS Visual C++ 2010,均在默认的"发布"模式下生成32位可执行文件.

注意,C++对两种方法使用完全相同的RAM量.在Fortran中,我会证明一些细微的差别,但我无法解释.对我而言,这看起来与Fortran本身或某些我不知道的英特尔Fortran编译器标志有关.

任何想法为什么会发生这种情况和/或有什么建议可以避免在Fortran中面向对象的方法中出现过多的RAM需求?

先感谢您.

Rob*_*Rob 9

要记住的一件事是分配二维数组和单维数组是不同的.例如:

  allocate(node_edges(10, 100)) 
Run Code Online (Sandbox Code Playgroud)

分配单个内存块,可以包含1000个项目.

  allocate(nodes(100)) ! 10000000 nodes
  do i = 1, 100
      allocate(nodes(i)%edges(10)) ! with 10 edges each
  end do
Run Code Online (Sandbox Code Playgroud)

分配一个块,可以包含100个项目,每个项目有10个子项目.相同数量的项目如此相同的内存使用?

在第二种情况下,您已经分配了100个新阵列.每个都有开销.在Fortran中,这可能非常高,因为它必须跟踪数组维度 - 您可能希望稍后获取数组部分.当分配大小很小时,这尤其明显.在这种情况下它是10并且使用额外的数组信息加上填充它可以使分配的大小加倍 - 它在你的情况下.

  • 英特尔Fortran文档显示,在64位计算机上,数组描述符为每个维度48字节加8字节.http://software.intel.com/sites/products/documentation/hpc/composerxe/en-us/2011Update/fortran/lin/bldaps_for/common/bldaps_hndl_arrdesc.htm (4认同)
  • 注释1:对于情况1和2,使用gfortran(在linux中)分别需要381.6 MiB和918.7 MiB.因此它不是编译器特定的问题.注释2:在情况2中反转大小,即每个具有10000000个边缘的10个节点(10个巨大的阵列对比我们以前的10000000个小阵列),还需要381.6 MiB.这表明正是这些额外信息导致了开销.现在,我不知道是否有解决方法.谢谢你们.(对不起,还没有足够的声誉投票) (2认同)
  • @ georg.balafas你不必为你的问题提供答案.接受它们是首要的事情. (2认同)