Fortran 释放阵列,但未在操作系统中发布



我有以下问题:如何在类型中释放数组内存?像 a%b%c, 如何解除分配 C?具体的问题是(我尝试的编译器环境是gfortran版本gcc4.4.7和ifort版本18.0.1.OS:linux):

module grist_domain_types
implicit none
public :: aaa 
type bbb 
real (8), allocatable   :: c(:)
end type bbb 
type aaa 
type(bbb),  allocatable :: b(:) 
end type aaa 
end module grist_domain_types
program main
use grist_domain_types
type(aaa) :: a
integer(4) :: time,i
time=20
allocate(a%b(1:100000000))
call sleep(time)!--------------1
do i=1,100000000
allocate(a%b(i)%c(1:1))
enddo
call sleep(time)!--------------2
do i=1,100000000
deallocate(a%b(i)%c)
enddo
call sleep(time)!--------------3
deallocate(a%b)
call sleep(time)!--------------4

end program

首先,"格福特兰主。F90 -o main"来编译程序,并运行此程序。然后我使用 top -p 进程 ID 来查看内存。当程序执行到1时,内存为4.5G。当程序执行到2时,内存为7.5G。当程序执行到3时,内存也是7.5G(但我认为是4.5G)。当程序执行到4时,内存为3G(我认为是0G或接近0G)。所以 dealpositionate(a%b(i)%c) 似乎不起作用。但是,我使用valgrind来查看记忆。这个程序的内存都被解除了...我使用了ifort和gfortran。无论我使用哪个编译器,都会发生此问题。如何解释这个问题? 我以这种方式分配了许多c数组,程序最终会因内存不足而崩溃。以及如何解决它?

看看英特尔论坛上的这篇文章。其中有 2 个重要信息:

  1. (来自福兰医生):

    当您执行 DEALLOCATE 时,分配的内存返回到内存分配器使用的池(在 Linux 和 OS X 上,这与 C 的 malloc/free 相同)。内存不会释放回操作系统 - 这甚至很少可能。经常发生的是,分配和解除分配的模式会导致虚拟内存碎片化,因此,虽然总可用空间可能很高,但可能没有足够的连续空间来分配大型项目。与磁盘不同,没有办法对内存进行"碎片整理"。

  2. (来自吉姆·登普西)

    查看是否可以按分配内存的相反顺序解除分配内存。这可以减少内存碎片。

您也可以参考其他英特尔帖子:

在程序运行期间,Fortran 运行时库将管理您的堆。是的,如果数据已解除分配,运行时可能会选择等待释放该内存。这是一个优化 - 如果你用相同的大小做另一个分配,它只会重用这些页面。如果堆开始不足,它将执行一些收集,但直到绝对必要为止。

另外,让我补充一些内容:检查作用域中是否没有动态创建的其他对象,例如自动数组或临时数组副本。这可能要求内存,只有当它们超出范围时才能释放。

总而言之,即使"top"表示内存仍在使用中,也应该开始担心只有当你的程序开始崩溃或Valgrind显示一些糟糕的东西时。

我修改了您的程序(以查看它在哪里)并在Windows 7/gFortran 7.2.0上运行。它不会在您报告时显示内存保留,因为内存恢复为 13 MB。与我的评论相反,内存需求在 c 初始化期间没有改变。

module grist_domain_types
implicit none
public :: aaa 
type bbb 
real (8), allocatable   :: c(:)
end type bbb 
type aaa 
type(bbb),  allocatable :: b(:) 
end type aaa 
end module grist_domain_types
program main
use grist_domain_types
type(aaa)  :: a
integer(4),parameter :: million = 1000000
integer(4) :: n = 100*million
integer(4) :: time = 5, i, pass
do pass = 1,5
write (*,*) ' go #', pass
allocate(a%b(1:n))
write (*,*) 'allocate b'
call sleep(time)!--------------1
write (*,*) ' go'
do i=1,n
allocate(a%b(i)%c(1:1))
enddo
write (*,*) 'allocate c'
call sleep(time)!--------------2
write (*,*) ' go'
do i=1,n
a%b(i)%c = real(i)
enddo
write (*,*) 'use c'
call sleep(time)!--------------2a
write (*,*) ' go'
do i=1,n
deallocate(a%b(i)%c)
enddo
write (*,*) 'deallocate c'
call sleep(time)!--------------3
write (*,*) ' go'
deallocate(a%b)
write (*,*) 'deallocate b'
call sleep(time)!--------------4
end do
write (*,*) ' done : exit ?'
read (*,*) i
end program

编辑:我已经重复测试,并通过...重复内存要求。这表明此 Fortran 程序没有内存泄漏。我使用任务管理器来识别此程序和操作系统的内存使用情况。您的特定 O/S 和 Fortran 编译器可能不同。

最新更新