Warning: file_get_contents(/data/phpspider/zhask/data//catemap/5/fortran/2.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181

Warning: file_get_contents(/data/phpspider/zhask/data//catemap/2/joomla/2.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
Memory management Fortran内存分配没有给出错误,但程序在初始化时被操作系统终止_Memory Management_Fortran - Fatal编程技术网

Memory management Fortran内存分配没有给出错误,但程序在初始化时被操作系统终止

Memory management Fortran内存分配没有给出错误,但程序在初始化时被操作系统终止,memory-management,fortran,Memory Management,Fortran,给出下面提供的最小工作示例,您知道为什么内存分配步骤中不会出现内存分配错误吗?正如我所检查的,当我使用valgrind来运行代码,或者将参数source=0.0添加到内存分配语句中时,正如预期的那样,出现了内存分配错误 更新:我用最少的工作示例再现了该问题: program memory_test implicit none double precision, dimension(:,:,:,:), allocatable :: sensitivity double preci

给出下面提供的最小工作示例,您知道为什么内存分配步骤中不会出现内存分配错误吗?正如我所检查的,当我使用valgrind来运行代码,或者将参数source=0.0添加到内存分配语句中时,正如预期的那样,出现了内存分配错误

更新:我用最少的工作示例再现了该问题:

 program memory_test

  implicit none

  double precision, dimension(:,:,:,:), allocatable :: sensitivity
  double precision, allocatable :: sa(:)
  double precision, allocatable :: sa2(:)

  integer :: ierr,nnz
  integer :: nx,ny,nz,ndata

  nx = 50
  ny = 50
  nz = 100
  ndata = 1600

  allocate(sensitivity(nx,ny,nz,ndata),stat=ierr)

  sensitivity = 1.0

  nnz = 100000000

  !allocate(sa(nnz),source=dble(0.0),stat=ierr)
  allocate(sa(nnz),stat=ierr)
  if(ierr /= 0) print*, 'Memory error!'

  !allocate(sa2(nnz),source=dble(0.0),stat=ierr)
  allocate(sa2(nnz),stat=ierr)
  if(ierr /= 0) print*, 'Memory error!'

  print*, 'Start initialization'

  sa = 0.0
  sa2 = 0.0

  print*, 'End initialization'

end program memory_test
当我运行它时,我没有消息“内存错误!”打印,但有消息“启动初始化”,然后程序被操作系统终止。如果我只使用带有“source”参数的内存分配(如代码中的注释),那么我会收到消息“memory error!”

对于内存统计,“free”命令提供以下输出:

             total       used       free     shared    buffers     cached
Mem:       8169952    3630284    4539668      46240       1684     124888
-/+ buffers/cache:    3503712    4666240
Swap:            0          0          0

延伸评论而非回答:

在Fortran中,初始化具有特定的含义;它是指在声明时设置变量的值。那么这个

real :: myvar = 0.0
是初始化。而这些

real :: myvar
....
myvar = 0.0
不是。现在,也许与你报道的问题更相关的是,这份声明

isensit%sa(:) = 0.0
将值
0.0
分配给数组部分的每个元素
isensit%sa(:)
。这(一旦你习惯了)与我认为你想写的内容非常不同,即:

isensit%sa = 0.0
此版本将值
0.0
分配给数组的每个元素
isensit%sa
。由于数组部分(即使是包含数组中每个元素的部分)不是数组,Fortran编译器在处理赋值时可能会临时为该部分分配空间。当您考虑更一般的数组部分时,这可能是有意义的

我不太明白为什么在执行
allocate
语句时,您认为空间没有分配,但我建议您先整理一下分配,然后再考虑。我猜临时分配给数组部分的空间,与数组本身消耗的空间一样多,可能会使程序崩溃,并导致您报告的行为

顺便说一句,你可以试试这个说法

allocate(isensit%sa(isensit%nnz),source=0.0,stat=ierr)
如果您的编译器是最新的,那么它应该在一条语句中进行分配并设置数组中的值


哦,还有一句毫无意义的话:宁愿
使用mpi
(或者
使用mpi\u mod
或者你的安装喜欢的任何东西
包括mpif.h
。这将阻止(许多)对mpi例程的调用与其要求不匹配可能导致的错误。使用例程关联意味着编译器可以检查参数匹配,但头文件的包含不匹配。

您看到了linux使用的内存分配策略的行为。当您分配内存但尚未写入时,它会仅包含在虚拟内存中(注意,这也可能受到特定Fortran运行库的影响,但我不确定)。此内存存在于您的进程虚拟地址空间中,但没有任何实际的物理内存页支持。只有当您写入内存时,才会分配物理页,并且仅足以满足写入要求

考虑以下计划:

program test
   implicit none
   real,allocatable :: array(:) 

   allocate(array(1000000000)) !4 gb array

   print *,'Check memory - 4 GB allocated'
   read *

   array(1:1000000) = 1.0

   print *,'Check memory - 4 MB assigned'
   read *

   array(1000000:100000000) = 2.0

   print *,'Check memory - 400 MB assigned'
   read *

   array = 5.0

   print *,'Check memory - 4 GB assigned'
   read *

end program
此程序分配4 GB内存,然后写入4 MB数组段、396 MB数组段(总写入=400 MB),最后写入整个数组(总写入=4 GB)。程序在每次写入之间暂停,以便查看内存使用情况

分配之后,第一次写入之前:

  PID USER      PR  NI    VIRT    RES    SHR S  %CPU %MEM     TIME+ COMMAND                                           
29192 casey     20   0 3921188   1176   1052 S   0.0  0.0   0:00.00 fortranalloc
所有的内存都是虚拟的(VIRT),只有一小部分由物理内存(RES)支持

在4 MB写入之后:

29192 casey     20   0 3921188   5992   1984 S   0.0  0.0   0:00.00 fortranalloc
29192 casey     20   0 3921188 392752   1984 S   0.0  1.6   0:00.18 fortranalloc
在396 MB写入之后:

29192 casey     20   0 3921188   5992   1984 S   0.0  0.0   0:00.00 fortranalloc
29192 casey     20   0 3921188 392752   1984 S   0.0  1.6   0:00.18 fortranalloc
在4 GB写入之后:

29192 casey     20   0 3921188 3.727g   1984 S  56.6 15.8   0:01.88 fortranalloc 
请注意,每次写入后,驻留内存都会增加以满足写入要求。这表明实际的物理内存分配仅在写入时发生,而不仅仅是在分配时发生,因此正常的
allocate()
无法检测错误。当您将
参数添加到
分配
时,会发生写入,这会导致内存的完全物理分配,如果失败,则可以检测到错误


您可能看到的是在内存耗尽时调用的linux。当这种情况发生时,OOM Killer将使用一种算法来确定要杀死什么以释放内存,并且您的代码的行为使其很有可能被杀死。当您的写入导致可以满足的物理分配时,您的进程正在停止由内核调用。您可以在写入时看到它(由赋值引起),但由于上面详述的行为,无法看到分配。

下面是调用
allocate()
的三种方法的比较:

这里使用的机器是Linux(x86_64),具有64-GB物理内存和64-GB交换磁盘。
ulimit-v
显示“无限”。在所有情况下(
method
=1,2,3),程序都会为
L
>120引发一个错误,即物理内存和交换内存的总和。对于
方法
=1,3,系统会引发一个错误

Operating system error: Cannot allocate memory
Allocation would exceed memory limit
而对于
method
=2,
stat=ierr
检测到一个错误。对于
L
<120,程序继续运行,其中
method
=2开始写入大量的0…无论如何,在这台机器上,
allocate()
允许的最大内存量似乎受到物理+交换大小的限制(一个合理的结果),尽管
ulimit-v
显示无限的虚拟内存


下面是使用
ulimit-v
限制
allocate()
所允许的最大内存量的另一个测试。此程序分配4GB数组并为2GB赋值

program alloc_test
    implicit none
    real, allocatable :: a(:), b(:)
    integer ierr, n

    n = 500000000

    allocate( a( n ), stat=ierr )   !! requests 2GB virtual memory
    if ( ierr /= 0 ) stop "Memory error! (a)"

    allocate( b( n ), stat=ierr )   !! requests 2GB virtual memory
    if ( ierr /= 0 ) stop "Memory error! (b)"

    print *, "before assignment (type any key)"
    call system( "ps aux | grep a.out" )
    read *

    print *, "now writing values..."
    a(:) = 0.0    !! request 2GB resident memory                        

    print *, "after assignment (type any key)"
    call system( "ps aux | grep a.out" )
    read *
end
如果我直接执行
/a.out
,此程序将在
分配()处不停止运行。
。我们现在基于

那么我们有

STOP Memory error! (a)
如果我们把它限制在2.2GB

STOP Memory error! (b)
最后,如果我们将其设置为>4GB,则分配开始

before assignment (type any key)
<username>    12380  0.0  0.0 3918048  652 pts/1    S+   07:59   0:00 ./a.out

now writing values...

after assignment (type any key)
<username>    12380 38.0  2.9 3918048 1953788 pts/1 S+   07:59   0:00 ./a.out