Bernie Nor
Bernie Nor

Reputation: 101

Testing for memory leak in Fortran (using pFUnit)

I've wrote my first program using allocatable. It works as expected. But, does it really? And more importantly, how can I set up a unit-test to catch memory leaks?

The idea behind the program is to allocate a chunck of storage room for my list of objects in the first place. And every time I add one more element more to the list than the allocated size, I double the allocation. I do this to reduce the number of allocations and subsequent copying of data from the old allocated memory, to the newly allocated memory.

I might over complicate this, but I'd like to spend some time now understanding the pitfalls, rather than falling head first into them a year or two down into the project.

The ode is compiled with gfortran 8.3.0 on linux. And using pFUnit 4.1. The code below is an extract to test only the allocation part.

Heres my test-program:

  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

Upvotes: 0

Views: 425

Answers (1)

Ian Bush
Ian Bush

Reputation: 7434

You will not get any memory leaks with this code. The reason is, and this is fundamental to the understanding of allocatable arrays, is that in Fortran 95 onwards it is required that allocatable arrays without the save attribute automatically get deallocated when they go out of scope. The nett result of this is that memory leaks for such arrays are impossible. This is one very good reason why you should prefer allocatable arrays to pointers. Related is the general software engineering principle of keeping the scope of variables as limited as possible, so that arrays are in memory for as short a period as possible.

Note this does not mean that you should never deallocate them as an array may remain in scope long after it is actually useful. Here "manual" deallocation may be of use. But it is not a memory leak.

Upvotes: 1

Related Questions