- Mark as New
- Bookmark
- Subscribe
- Mute
- Subscribe to RSS Feed
- Permalink
- Report Inappropriate Content
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:
[fortran]
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
[/fortran]
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
[fortran] final :: FinalizeContainer [/fortran]
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
Link Copied
- Mark as New
- Bookmark
- Subscribe
- Mute
- Subscribe to RSS Feed
- Permalink
- Report Inappropriate Content
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...
- Mark as New
- Bookmark
- Subscribe
- Mute
- Subscribe to RSS Feed
- Permalink
- Report Inappropriate Content
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).
- Mark as New
- Bookmark
- Subscribe
- Mute
- Subscribe to RSS Feed
- Permalink
- Report Inappropriate Content
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.

- Subscribe to RSS Feed
- Mark Topic as New
- Mark Topic as Read
- Float this Topic for Current User
- Bookmark
- Subscribe
- Printer Friendly Page