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

时间:2015-02-16 19:06:32

标签: memory-leaks fortran null-pointer derived-types

虽然我编写了最终的程序,但我定义了一个派生类型并遇到了内存释放的一些问题。代码如下

module ModuleCoordinate
  implicit none

  type :: TCoordinate
    real(8),dimension(:),pointer :: Coordinate => NULL()
    contains
      procedure :: TCoordinateAssignment
      generic,public :: Assignment(=) => TCoordinateAssignment
      final :: TCoordinateDel
  end type TCoordinate

  interface TCoordinate
    module procedure :: TCoordinateInit
  end interface TCoordinate

  contains
    subroutine TCoordinateDel(self)
      type(TCoordinate),intent(inout) :: self
      if(associated(self%Coordinate))deallocate(self%Coordinate)
    end subroutine TCoordinateDel

    subroutine TCoordinateAssignment(O1,O2)
      class(TCoordinate),intent(out) :: O1
      type(TCoordinate),intent(in) :: O2
      if(associated(O2%Coordinate))allocate(O1%Coordinate,source=O2%Coordinate)
    end subroutine TCoordinateAssignment

    type(TCoordinate) function TCoordinateInit(IVal1,IVal2) result(self)
      real(8),intent(in) :: IVal1,IVal2
      allocate(self%Coordinate(2))
      self%Coordinate=(/IVal1,IVal2/)
    end function TCoordinateInit
end module ModuleCoordinate

测试代码如下

program test
  implicit none
  integer(4),parameter :: NLoop=40000
  integer(4) :: i
  do i=1,NLoop
    call TestMemory1()
    call TestMemory2()
  end do
  pause
end program test

subroutine TestMemory1()
  use ModuleCoordinate
  implicit none
  integer(4),parameter :: DN=10
  integer(4) :: i
  type(TCoordinate),dimension(DN) :: a
  do i=1,DN
    a(i)=TCoordinate(1.0_8,1.0_8)
  end do
end subroutine TestMemory1

subroutine TestMemory2()
  use ModuleCoordinate
  implicit none
  type(TCoordinate) :: b1,b2,b3,b4,b5,b6,b7,b8,b9,b10
  b1=TCoordinate(1.0_8,1.0_8)
  b2=TCoordinate(1.0_8,1.0_8)
  b3=TCoordinate(1.0_8,1.0_8)
  b4=TCoordinate(1.0_8,1.0_8)
  b5=TCoordinate(1.0_8,1.0_8)
  b6=TCoordinate(1.0_8,1.0_8)
  b7=TCoordinate(1.0_8,1.0_8)
  b8=TCoordinate(1.0_8,1.0_8)
  b9=TCoordinate(1.0_8,1.0_8)
  b10=TCoordinate(1.0_8,1.0_8)
end subroutine TestMemory2

事实证明子例程TestMemory2是正常的,而TestMemory1不是,这意味着当声明此派生类型的数组时,最终的过程不起作用并且内存泄漏

但是,如果我删除此派生类型定义中=> NULL()右侧的Coordinate,则两个子例程似乎都能正常工作。

指针Coordinate被解除分配时有什么不同?  如果重要的话,编译器是ifort_2013_sp1.3.174。

1 个答案:

答案 0 :(得分:1)

在最终确定过程的描述中,我们看到了(Fortran 2008,4.5.6.2)

  

如果实体的动态类型具有最终子例程,其伪参数具有与要最终确定的实体相同的种类类型参数和等级,则使用实体作为实际参数调用它。否则,如果存在其伪参数具有相同的基本最终子例程   kind类型参数作为正在完成的实体,它被实体作为实际参数调用。否则,此时不会调用子程序。

只有标量(rank-0)实体提供了派生类型的最终子例程。要对你的rank-1实体进行最终确定,最简单的方法(在这种情况下似乎是)使子程序成为元素。

我有点不愿意提及=>NULL()方面,因为我目前没有测试我将要编写的内容的方法,但我会推测。

如果没有=>NULL()默认初始化,则指针组件具有未定义的关联状态。这意味着,当你这样做时

    b1=TCoordinate(1.0_8,1.0_8)
有趣的事情发生了。

作为作业的一部分b1在进入TCoordinateAssignment时最终确定。最终化涉及使用未定义关联状态的指针调用associated。这是不允许的(结果可能会产生任何结果)。