Skip to content

Memory management

Dave Robinson edited this page Jun 13, 2014 · 4 revisions

Coding rules

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.

Tutorial

Fortran 95 offers several mechanisms for dynamic memory management. The most important for local memory space are automatic arrays and allocatable arrays.

Automatic 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.

Automatic function result sizes

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

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.

Clone this wiki locally