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

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

问题描述

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

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

测试代码如下

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 不是,这意味着当声明这个派生类型的数组时,最终过程不起作用和内存泄漏.

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.

但是,如果我删除 =>;在这个派生类型的定义中Coordinate右侧的NULL(),两个子程序似乎都运行良好.

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.

当指针 Coordinate 被释放时有什么不同?如果重要的话,编译器是 ifort_2013_sp1.3.174.

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

推荐答案

在对定稿过程的描述中我们看到 (Fortran 2008, 4.5.6.2)

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

如果实体的动态类型有一个最终子例程,其伪参数与被终结的实体具有相同的类型参数和等级,则以实体作为实际参数调用它.否则,如果存在一个基本的最终子程序,其虚拟参数具有相同的kind 类型参数作为被最终确定的实体,它以实体作为实际参数被调用.否则,此时不会调用任何子程序.

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.

只有为标量 (rank-0) 实体提供的派生类型的最终子例程.要最终确定您的 1 级实体,最简单的方法(在本例中似乎是这样)是使您拥有的子程序成为元素.

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.

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

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.

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

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)

有趣的事情发生了.

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

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天全站免登陆