Тестирование на утечку памяти в Fortran (с использованием pFUnit) - PullRequest
0 голосов
/ 20 февраля 2020

Я написал свою первую программу с использованием allocatable. Работает как положено. Но так ли это на самом деле? И что еще более важно, как я могу настроить юнит-тест для обнаружения утечек памяти?

Идея программы заключается в том, чтобы сначала выделить кусок памяти для моего списка объектов. И каждый раз, когда я добавляю в список на один элемент больше, чем выделенный размер, я удваиваю распределение. Я делаю это, чтобы уменьшить количество выделений и последующее копирование данных из старой выделенной памяти во вновь выделенную память.

Я мог бы усложнить это, но сейчас я хотел бы потратить некоторое время на понимание ловушек, вместо того, чтобы падать головой в них через год или два в проект.

Ода скомпилирована с gfortran 8.3.0 на linux. И с помощью 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

1 Ответ

1 голос
/ 20 февраля 2020

Вы не получите никаких утечек памяти с этим кодом. Причина в том, что это является фундаментальным для понимания распределенных массивов, состоит в том, что в Fortran 95 и далее требуется, чтобы массивы allocatable без атрибута save автоматически освобождались, когда они go выходят из области видимости. Конечным результатом этого является то, что утечки памяти для таких массивов невозможны. Это одна из очень веских причин, почему вы должны предпочесть allocatable массивы pointer с. С этим связан общий принцип разработки программного обеспечения, заключающийся в том, чтобы ограничивать область действия переменных настолько, насколько это возможно, чтобы массивы находились в памяти как можно более короткий период.

Обратите внимание, это не означает, что вы никогда не должны освобождать их как массив может оставаться в области видимости еще долго после того, как он действительно будет полезен. Здесь «ручное» освобождение может быть полезным. Но это не утечка памяти.

...