在 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 数组而不是 pointers 的一个很好的理由。相关的是保持变量范围尽可能有限的一般软件工程原则,以便数组在内存中的时间尽可能短。

请注意,这并不意味着您永远不应解除分配它们,因为数组可能在实际有用后很长时间仍保留在范围内。这里“手动”释放可能有用。但这不是内存泄漏。

【讨论】:

以上是关于在 Fortran 中测试内存泄漏(使用 pFUnit)的主要内容,如果未能解决你的问题,请参考以下文章

尽管已完成,但派生类型的 Fortran 数组和内存泄漏

fortran 有垃圾收集器(gc)吗?

内存泄漏单元测试 C++

如何检测内存泄漏

如何在移动设备中测试我的应用程序的内存泄漏,尤其是在 iOS 和 Android 中? [关闭]

移动端专项测试-内存泄漏