Automatic Memory Cleanup with Fortran ALLOCATABLE Arrays
Local Fortran ALLOCATABLE arrays are freed automatically when a subroutine returns—here is how to use it safely and what still requires manual care.
29 Sept 2026, 06:48 UTC

Useful answer
If you allocate a scratch array inside a Fortran subroutine and never call DEALLOCATE, the memory is still released when the subroutine returns—provided the array is declared ALLOCATABLE and not POINTER. This automatic deallocation has been part of the language since Fortran 2003. For engineering solvers that call the same routine thousands of times, relying on this rule removes a common source of memory leaks without changing the algorithm.
How automatic deallocation works
An ALLOCATABLE array owns its memory. When the variable goes out of scope—typically at the end of a subroutine or function—the Fortran runtime inserts a deallocation for you. A POINTER, by contrast, is an alias to memory owned by something else; the runtime does not free the target when the pointer goes out of scope, so pointer targets can leak unless you deallocate them explicitly.
The distinction matters because both attributes use ALLOCATE and DEALLOCATE, but only allocatable variables receive automatic cleanup at scope exit.
Worked configuration: scratch array in an iterative solver
The following module allocates a work array inside solve_step, uses it, and returns without an explicit DEALLOCATE.
module solver_utils
implicit none
private
public :: solve_step
contains
subroutine solve_step(n, result)
integer, intent(in) :: n
real(8), intent(out) :: result
real(8), allocatable :: work(:)
integer :: i
! Allocate scratch memory for this call only.
allocate(work(n))
do i = 1, n
work(i) = dble(i) * 0.5_8
end do
result = sum(work)
! No DEALLOCATE(work) is required here.
! work is automatically deallocated when this subroutine returns.
end subroutine solve_step
end module solver_utils
program test_automatic_dealloc
use solver_utils
implicit none
real(8) :: total
integer :: k
do k = 1, 100000
call solve_step(1000, total)
end do
print *, "Final total:", total
end program test_automatic_dealloc
Compile from a terminal with bounds checking enabled. No special permissions are required.
gfortran -fcheck=all -Wall -Wextra -o solver solver_utils.f90
Run the executable:
./solver
Expected checks: the compiler exits with status zero, and the program prints a final total without a runtime allocation or deallocation error. Because -fcheck=all adds runtime overhead, use it for debugging and remove it for production timing runs.
To confirm memory behavior externally, run under a memory tracker such as valgrind:
valgrind --leak-check=full ./solver
Valgrind is a diagnostic tool, not part of Fortran. It slows execution substantially and is optional. Inspect the leak summary yourself; do not treat the absence of visible output as proof.
Limits and common mistakes
| Situation | Behavior | Risk |
|---|---|---|
| Local allocatable array, no explicit DEALLOCATE | Freed automatically at scope exit | None under standard Fortran 2003+ semantics |
| Pointer variable | Not automatically freed when the pointer goes out of scope | Memory leak if the target was allocated and not deallocated elsewhere |
| DEALLOCATE on an unallocated allocatable | Runtime error | Program aborts; check status with ALLOCATED(work) before deallocating |
| Allocatable with TARGET referenced by a pointer | Pointer may dangle after automatic deallocation | Invalid memory access if the pointer is used after the allocatable is freed |
| Module-level allocatable variable | Persists for the program lifetime unless explicitly deallocated | Not freed at subroutine scope; can accumulate across calls |
Common mistake: mixing POINTER and ALLOCATABLE
Do not assume that because you used ALLOCATE, the memory cleans itself up. If you declare real(8), pointer :: ptr(:) and allocate it, the pointer must be deallocated explicitly or its target must be deallocated through another allocatable owner. Mixing the two attributes in the same scope without tracking ownership is a frequent cause of double-frees or leaks.
Common mistake: manual DEALLOCATE before return
Calling DEALLOCATE(work) and then letting the subroutine end is safe only if you do not deallocate again. Some older codebases deallocate every scratch array at the end of every routine out of habit. That is not wrong, but it is unnecessary for local allocatable variables and adds maintenance risk if the routine has multiple return paths.
Practical verification
- Compile with
gfortran -fcheck=all -Wall -Wextrato catch allocation mismatches at runtime. - Run the program normally and confirm it completes with exit status zero.
- Optionally run under
valgrind --leak-check=fulland inspect the leak summary for the process. - If you add manual
DEALLOCATEcalls, guard them withif (allocated(work)) deallocate(work)to avoid runtime errors on already-freed arrays.
Automatic deallocation applies to local allocatable variables in procedures and block constructs. It does not replace explicit memory management for allocatable components of derived types unless you write a finalizer, nor does it apply to memory allocated through C interoperability pointers.
For long-running engineering codes, prefer local ALLOCATABLE scratch arrays over persistent module-level arrays when the scratch data is only needed inside one call. This keeps memory usage bounded by the largest single call rather than the sum of all calls.
0 replies
A thoughtful contribution can make all the difference. Be the first to share one.