Vit*_*liy 4 fortran memory-management
鉴于下面提供的最小工作示例,您知道为什么在内存分配步骤中不会发生内存分配错误吗?正如我检查的那样,当我使用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
Run Code Online (Sandbox Code Playgroud)
当我运行它时,我没有消息"内存错误!" 打印,但有消息'开始初始化'然后该程序被操作系统杀死.如果我使用'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
Run Code Online (Sandbox Code Playgroud)
您正在看到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
Run Code Online (Sandbox Code Playgroud)
该程序分配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
Run Code Online (Sandbox Code Playgroud)
所有内存都是虚拟的(VIRT),只有一小部分由物理内存(RES)支持.
4 MB写完后:
29192 casey 20 0 3921188 5992 1984 S 0.0 0.0 0:00.00 fortranalloc
Run Code Online (Sandbox Code Playgroud)
写完396 MB之后:
29192 casey 20 0 3921188 392752 1984 S 0.0 1.6 0:00.18 fortranalloc
Run Code Online (Sandbox Code Playgroud)
并在4 GB写入后:
29192 casey 20 0 3921188 3.727g 1984 S 56.6 15.8 0:01.88 fortranalloc
Run Code Online (Sandbox Code Playgroud)
注意,在每次写入之后,驻留存储器增加以满足写入.这表明实际的物理内存分配仅在写入时发生,而不仅仅在分配时发生,因此法线allocate()
无法检测到错误.当您添加source
参数allocate
时,会发生写入,这会导致内存的完全物理分配,如果失败,则可以检测到错误.
您可能会看到的是当内存耗尽时调用的Linux OOM Killer.当发生这种情况时,OOM Killer将使用算法来确定要释放内存的内容,并且代码的行为使其成为很可能被杀死的候选者.当您的写入导致可以满足的物理分配时,您的进程将被内核杀死.您在写入时看到它(由赋值引起)但由于上面详述的行为而没有分配.
归档时间: |
|
查看次数: |
5394 次 |
最近记录: |