Fortran数组派生类型和内存泄漏,尽管最终确定 [英] Fortran array of derived types and memory leaks despite finalization

查看:332
本文介绍了Fortran数组派生类型和内存泄漏,尽管最终确定的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我定义了一个派生类型,并且遇到了一些内存释放问题,尽管我已经编写了最终的过程。代码如下:

 模块ModuleCoordinate 
隐式无

类型:: TCoordinate
real(8),dimension(:),pointer :: Coordinate => NULL()
包含
procedure :: TCoordinateAssignment
generic,public :: Assignment(=)=> TCoordinateAssignment
final :: TCoordinateDel
结束类型TCoordinate

接口TCoordinate
模块过程:: TCoordinateInit
结束接口TCoordinate

包含
子例程TCoordinateDel(self)
type(TCoordinate),intent(inout):: self
if(associated(self%Coordinate))deallocate(self%Coordinate)
end子程序TCoordinateDel

子程序TCoordinateAssignment(O1,O2)
class(TCoordinate),intent(out):: O1
type(TCoordinate),intent(in):: O2 $ (相关(O2%坐标))分配(O1%坐标,源= O2%坐标)
结束子程序TCoordinateAssignment

类型(TC坐标)函数TCoordinateInit(IVal1,IVal2) result(self)
real(8),intent(in):: IVal1,IVal2
allocate(self%Coordinate(2))
self%Coordinate =(/ IVal1,IVal2 /)
结束函数TCoordinateInit
结束模块ModuleCoordinate

测试代码如下所示:

 程序测试
隐式无
整数(4),参数:: NLoop = 40000
整数(4):: i
do i = 1,NLoop
调用TestMemory1()
调用TestMemory2()
end do
暂停
结束程序测试

子程序TestMemory1()
使用ModuleCoordinate
隐式无
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
结束子程序TestMemory1

子程序TestMemory2()
使用ModuleCoordinate
隐式无
类型(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)
结束子程序TestMemory2

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



然而, ,如果我删除 =>在这个派生类型的定义中, Coordinate 右边的NULL(),这两个子例程似乎都工作正常。

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

解决方案

在描述最终化过程时,
$ b


如果实体的动态类型有一个最终子例程,其伪参数具有相同的类型参数和rank作为最终确定的实体,它被称为实体作为实际参数。否则,如果存在元素最终子例程,其伪参数与正在定型的实体具有相同的
类型参数,则将其作为实际参数调用。


仅为标量提供了派生类型的最后一个子例程(等级为0 )实体。要为你的rank-1实体定稿,最简单的方法(在这种情况下,看起来就是)使你的子程序具有元素。



我略微不情愿提及 => NULL()方面,因为我目前没有测试我要写什么的方法,但是我会推测。



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

  b1 = TCoordinate(1.0_8,1.0_8)
$ b

作为赋值的一部分 b1 在输入 TCoordinateAssignment 时结束。最终确定包括使用未定义关联状态的指针调用关联。这是不允许的(结果可能会产生任何结果)。

I defined a derived type and encountered some problems with memory deallocation although I had written the final procedure. The code is as follows

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

The test code is as follows

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

It turns out that the subroutine TestMemory2 is OK while TestMemory1 is not, which means that when an array of this derived type is declared the final procedure doesn't work and the memory leaks.

However, if I delete the => NULL() on the right of the Coordinate in the definition of this derived type, both subroutines seem to work well.

What makes the difference when the pointer Coordinate is being deallocated? The complier is ifort_2013_sp1.3.174 if it matters.

解决方案

In the description of the finalization process we see (Fortran 2008, 4.5.6.2)

If the dynamic type of the entity has a final subroutine whose dummy argument has the same kind type parameters and rank as the entity being finalized, it is called with the entity as an actual argument. Otherwise, if there is an elemental final subroutine whose dummy argument has the same kind type parameters as the entity being finalized, it is called with the entity as an actual argument. Otherwise, no subroutine is called at this point.

There is a final subroutine for the derived type provided only for scalar (rank-0) entities. To have finalization for your rank-1 entity the simplest way (it seems, in this case) is to make the subroutine you have elemental.

I'm slightly reluctant to mention the =>NULL() aspect as I have no current means of testing what I'm about to write, but I'll speculate.

Without the =>NULL() default initialization the pointer component has undefined association status. This means, that when you do

    b1=TCoordinate(1.0_8,1.0_8)

interesting things happen.

As part of the assignment b1 is finalized on entry to TCoordinateAssignment. The finalization involves calling associated with the pointer which is of undefined association status. This is not allowed (with the consequence that any result could come about).

这篇关于Fortran数组派生类型和内存泄漏,尽管最终确定的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆