Fortran数组派生类型和内存泄漏,尽管最终确定 [英] Fortran array of derived types and memory leaks despite finalization
问题描述
我定义了一个派生类型,并且遇到了一些内存释放问题,尽管我已经编写了最终的过程。代码如下:
模块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)
$ c $ $ 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屋!