Finalization subroutine questions

Finalization subroutine questions

 

Hi,

I'm trying to solve a memory leak in a Fortran program and I'm seeing some issues with finalization routines. The following example illustrates the issue that I found:

module MemLeaksMod

	  implicit none

	 

	  type :: ComponentType 

	    private

	    real :: value

	  contains

	    final :: FinalizeComponent

	  end type ComponentType  
  type :: ContainerType

	    class(ComponentType), allocatable :: component

	  contains

	    final :: FinalizeContainer

	  end type ContainerType

	  

	contains

	  subroutine FinalizeContainer(this)

	    type(ContainerType), intent(inout) :: this    

	    print *, "Finalizing container class"

	  end subroutine FinalizeContainer
  subroutine FinalizeComponent(this)

	    type(ComponentType), intent(inout) :: this  

	    print *, "Finalizing component class"

	    end subroutine FinalizeComponent

	end module MemLeaksMod

	  

	program MemLeaksProg

	  use MemLeaksMod

	  implicit none

	  call TestMemLeaks()

	 contains

	    ! Shows that the finalizer of the componentType class isn't called if the containerType class doesn't have a finalizer:

	  subroutine TestMemLeaks

	    type(ContainerType) :: container

	    allocate(container%component)

	  end subroutine TestMemLeaks

	 end program MemLeaksProg

	

When running the program, I get the following output: 

 Finalizing container class
 Finalizing component class

This is what I expect. Now if I comment out the 

     final :: FinalizeContainer 

statement for the container type, I would expect that the finalizer for ComponentType is still called. However, when running the modified code, it shows now output, so the finalizer for ComponentType wasn't called.

Is this a bug in the intel compiler or is it the expected behaviour? For me it seems that calling the ComponentType finalizer shouldn't depend on the presence of a finalizer on the ContainerType.

Another question related to finalizers. If a type has allocatable components and implements a finalizer, should the finalizer deallocate the allocatable components, or will this be done automatically (as is the case if no finalizer was implemented at all)? I tried to find the answer in "Model Fortran Explained", but it wasn't clear on this subject.

Best regards,
Erik

4 posts / 0 new
Last post
For more complete information about compiler optimizations, see our Optimization Notice.

This is something that I've been wondering about for a while.   See this post from a while back.  And maybe this one.  The latter is reassuring, because at least I've been consistent over a year or two in being confused.

A type is finalizable if it has a final binding or a non-pointer, non-allocatable component of finalizable type (4.5.6.1p2).

With a final binding, as presented, your container type meets the first half of that condition, so it is finalizable.  When you remove the final binding, it is not - there is a component that is of finalizable type, but it is allocatable, so the second half of the condition doesn't apply.  But what does that mean...?  The Intel compiler appears to think that because the component is no longer part of a finalizable type, it isn't finalized. 

But... an allocatable component is a allocatable "entity", entity just being a fancy way of writing "thing".  And "when an allocatable entity is deallocated, it is finalized" (4.5.6.3p1). 

And when an unsaved local variable of derived type goes "out of scope" (using general terminology), any allocatable components are deallocated (6.7.3.2.p2 and p3, basically, being mindful that components of a local variable are themselves a local variable). 

[That actually answers your second question - finalization and deallocation are linked in terms of timing, but they are still separate "actions" - you don't need to deallocate allocatable components in your finalizers.]

So completely independent of the "finalizable" status of the parent (container) object, we've got a trigger for finalization, of something that is finalizable.  Which I take to mean... that `component` in your example should be finalized.  The parent `container` thing being finalizable just gives the programmer more control over the sequence of finalization - the programmer can (if they want to... they don't have to as per the [ ] bit above) explicitly deallocate an allocatable component in the finalizer of the parent to ensure a certain finalization order. 

At least, I hope this is the case, because otherwise there's a nasty and confusing difference between explicit deallocation and automatic deallocation.  My hope does implicitly require that there's a prohibition of finalizing something twice.

But I have to admit, I don't understand why the standard has been written the way it has.  Something doesn't quite seem right with respect to allocatable components.  Why are they significant in determining whether a type is finalizable?  What does the term "finalizable component" mean?  Perhaps the good doctor could shed some light...

I think the key point here is from 4.5.6.3p1 "When an allocatable entity is deallocated, it is finalized." which suggests that the (implicit) deallocation of container%component at the end of TestMemLeaks should call FinalizeComponent regardless of whether ContainerType is finalizable of not.

My interpretation of 4.5.6.1p2 is that it enables a non-allocatable non-pointer component of a type to be finalized as per 4.5.6.2p1 (2) even if the type has no final procedure(s) declared.

For example, if component is declared instead in ContainerType as

type(ComponentType) :: component

you should expect FinalizeComponent to be called at the end of TestMemLeaks regardless of whether ContainerType has a final procedure or not (which seems to be what is happening, at least with XE 2013 SP1 Update 1).

Thanks for the replies. It's good to know that I'm not the only one who's confused about finalizers. 

I found some other issues with finalizers as well, but since I'm running an older version of the intel compiler, probably I should first try with the latest version. For the moment I won't be doing this since our project runs into this error (http://software.intel.com/en-us/forums/topic/487151) with the latest version of the compiler. 

Leave a Comment

Please sign in to add a comment. Not a member? Join today