-
Notifications
You must be signed in to change notification settings - Fork 115
Memory management
Where a procedure requires local variables whose size is known only at runtime, those variables should utilise dynamic memory allocation locally. Work space should not be passed down from higher level routines.
Automatic arrays, which many Fortran compilers place on the stack, are suitable for smaller variables. Variables whose size is that of a single element or another small part of a problem space should generally be automatic variables. For example arrays whose dimensions are ngi
or nloc
are good candidates.
Automatic arrays are not suitable for arrays which could become very large, for example arrays whose dimensions are nonods
or totele are too big to be automatic arrays. These large arrays should be declared as allocatable and explicitly allocated and deallocated.
Fortran 95 offers several mechanisms for dynamic memory management. The most important for local memory space are automatic arrays and allocatable arrays.
Automatic arrays are data objects whose extent is calculated when a procedure is called. Their sizes can depend on the value of one of the procedure's arguments or on some other quantity which can be calculated at run time - for example the size of one of the arguments.
The following example displays the use of automatic arrays:
subroutine array_example(vector, scalar)
! A subroutine showing the use of automatic arrays.
real, dimension(:), intent(inout) :: vector
integer, intent(in) :: scalar
! A local array the same size as vector
real, dimension(size(vector)) :: local_vector1
! A local array who's size is calculated from scalar.
logical, dimension(2*scalar+1) :: local_vector2
---- the code goes here ----
end subroutine array_example
Automatic arrays start uninitialised every time the procedure is entered and are automatically destroyed when the subroutine exits.
The result of a function can also be automatically determined:
function automagic(vector)
! A function who's result is the same size as its argument.
real, dimension(:,:), intent(in) :: vector
! Note that vector had to be declared before we could use it to
! calculate the size of automagic.
real, dimension(size(vector,1),size(vector,2)) :: automagic
---- the code goes here ----
end function automagic
Allocatable arrays are declared with a fixed number of dimensions but with no extents. Before they are used, they must have memory allocated to them with the allocate statement. When the variable is finished with, or before calling allocate again to change the size of the array, it is necessary to free the memory used using the deallocate statement.
The following example demonstrates the use of allocatable arrays in a subroutine.
subroutine allocate_example(sizes, ....)
integer, dimension(:), intent(in) :: sizes
real, dimension(:), allocatable :: foo
integer :: i
! Allocate the first time:
allocate(foo(sizes(1))
do i=1,size(sizes)
if (size(foo)/=size(i)) then
deallocate(foo)
allocate(foo(size(i))
end
---- some code using foo ----
end do
! No need to deallocate foo - it's automatically deallocated when we
! leave the subroutine.
end subroutine allocate_example
As noted above, an allocatable array is automatically deallocated when the subroutine it's declared it returns. If this behaviour is not desired then an allocatable array can be given the save attribute. This will cause both the allocation state and the contents of the variable to be preserved between procedure calls. Allocatable arrays can also be declared in modules, this is a good way of storing data which is global for a particular module. Allocatable arrays defined in modules should almost always be given the save attribute to prevent their values being lost when execution passes to other parts of the program.