在 Fortran 中测试内存泄漏(使用 pFUnit)
Posted
技术标签:
【中文标题】在 Fortran 中测试内存泄漏(使用 pFUnit)【英文标题】:Testing for memory leak in Fortran (using pFUnit) 【发布时间】:2020-02-19 21:16:45 【问题描述】:我已经使用 allocatable 编写了我的第一个程序。它按预期工作。但是,真的吗?更重要的是,如何设置单元测试来捕获内存泄漏?
该程序背后的想法是首先为我的对象列表分配一大块存储空间。每次我在列表中添加比分配大小多一个元素时,我都会将分配加倍。我这样做是为了减少分配次数以及随后将数据从旧分配的内存复制到新分配的内存。
我可能会让这件事变得过于复杂,但我现在想花一些时间来了解其中的陷阱,而不是在项目进行一两年后就陷入困境。
ode 在 linux 上使用 gfortran 8.3.0 编译。并使用 pFUnit 4.1。下面的代码是仅测试分配部分的摘录。
这是我的测试程序:
program test_realloc
use class_test_malloc
integer :: i
real :: x, y
type(tmalloc) :: myobject
call myobject%initialize()
do i=1, 100
x = i * i
y = sqrt(x)
call myobject%add_nbcell(i, x, y)
end do
call myobject%dump()
end program test_realloc
array_reallocation.f:
!
! Simple test to see if my understanding of dynamicly allocation
! of arrays is correct.
!
module class_test_malloc
use testinglistobj
implicit none
type tmalloc
integer :: numnbcells, maxnbcells
type(listobj), allocatable :: nbcells(:)
contains
procedure, public :: initialize => init
procedure, public :: add_nbcell ! Might be private?
procedure, private :: expand_nbcells
procedure, public :: dump
end type tmalloc
contains
subroutine init(this)
class(tmalloc), intent(inout) :: this
this%numnbcells = 0
this%maxnbcells = 4
allocate (this%nbcells(this%maxnbcells))
end subroutine init
subroutine add_nbcell(this, idx, x, y)
class(tmalloc), intent(inout) :: this
integer, intent(in) :: idx
real, intent(in) :: x, y
type(listobj) :: nbcell
if(this%numnbcells .eq. this%maxnbcells) then
call this%expand_nbcells()
print *,"Expanding"
endif
this%numnbcells = this%numnbcells + 1
nbcell%idx = idx
nbcell%x = x
nbcell%y = y
this%nbcells(this%numnbcells) = nbcell
print *,"Adding"
end subroutine add_nbcell
subroutine expand_nbcells(this)
class(tmalloc), intent(inout) :: this
type(listobj), allocatable :: tmpnbcells(:)
integer :: size
size = this%maxnbcells *2
allocate (tmpnbcells(size))
tmpnbcells(1:this%maxnbcells) = this%nbcells
call move_alloc( from=tmpnbcells, to=this%nbcells)
this%maxnbcells = size
end subroutine
subroutine dump(this)
class(tmalloc), intent(inout) :: this
integer :: i
do i=1, this%numnbcells
print*, this%nbcells(i)%x, this%nbcells(i)%y
end do
end subroutine
end module
listobj.f:
module testinglistobj
type listobj
integer :: idx
real :: x
real :: y
end type
end module testinglistobj
【问题讨论】:
作为一般规则,如果您使用可分配对象并且存在内存泄漏,那是编译器编写者的错,而不是您的错。 原则上没有问题。你有具体的担心理由吗?如果是这样,有一些工具可以提供帮助 [首先,gfortran 的-Wall
和 -fcheck=all
标志(后者不适用于“生产运行”,因为它启用运行时检查),valgrind 也可能有帮助]。有什么理由提到 pfunit?
【参考方案1】:
使用此代码不会导致任何内存泄漏。原因是,这是理解可分配数组的基础,因为在 Fortran 95 及更高版本中,没有save
属性的allocatable
数组在超出范围时需要自动解除分配。这样做的最终结果是此类数组的内存泄漏是不可能的。这是您应该更喜欢 allocatable
数组而不是 pointer
s 的一个很好的理由。相关的是保持变量范围尽可能有限的一般软件工程原则,以便数组在内存中的时间尽可能短。
请注意,这并不意味着您永远不应解除分配它们,因为数组可能在实际有用后很长时间仍保留在范围内。这里“手动”释放可能有用。但这不是内存泄漏。
【讨论】:
以上是关于在 Fortran 中测试内存泄漏(使用 pFUnit)的主要内容,如果未能解决你的问题,请参考以下文章