I was trying to find some information as to why the keyword new
can be used to dynamically allocate objects but there is no keyword like delete
that could be used to deallocate them. Going through mentions of Ada.Unchecked_Deallocation
in Ada 2012 Reference Manual I found a few interesting excerpts:
Every object is finalized before being destroyed (for example, by leaving a subprogram_body containing an object_declaration, or by a call to an instance of Unchecked_Deallocation)
Each access-to-object type has an associated storage pool. The storage allocated by an allocator comes from the pool; instances of Unchecked_Deallocation return storage to the pool.
The Deallocate procedure of a user-defined storage pool object P may be called by the implementation to deallocate storage for a type T whose pool is P only at the places when an Allocate call is allowed for P, during the execution of an instance of Unchecked_Deallocation for T, or as part of the finalization of the collection of T.
If I had to guess, what that means is that it is possible for an implementation to automatically deallocate an object associated with an access when the execution leaves the scope in which access was declared. No need for explicit calls to Unchecked_Deallocation
.
This seems to be supported by a section in Ada 95 Quality and Style Guide which states:
The unchecked storage deallocation mechanism is one method for overriding the default time at which allocated storage is reclaimed. The earliest default time is when an object is no longer accessible, for example, when control leaves the scope where an access type was declared (the exact point after this time is implementation-dependent). Any unchecked deallocation of storage performed prior to this may result in an erroneous Ada program if an attempt is made to access the object.
But the wording is rather unclear. If I were to run this code, what exactly would happen on the memory side of things?
with Ada.Text_IO; use Ada.Text_IO;
procedure Main is
procedure Run is
X : access Integer := new Integer'(64);
begin
Put (Integer'Image (X.all));
end Run;
begin
for I in 1 .. 16 loop
Run;
end loop;
end Main;
with Ada.Text_IO; use Ada.Text_IO;
procedure Main is
procedure Outer is
type Integer_Access is not null access Integer;
procedure Run is
Y : Integer_Access := new Integer'(64);
begin
Put (Integer'Image (Y.all));
end Run;
begin
for I in 1 .. 16 loop
Run;
end loop;
end Outer;
begin
Outer;
end Main;
Is there a guaranteed memory leak or is X
deallocated when Run
finishes?
As outlined in Memory Management with Ada 2012, cited here, a local variable is typically allocated on a stack; its memory is automatically released when the variable's scope exits. In contrast, a dynamic a variable is typically allocated on a heap; its memory is allocated using new
, and its memory must be reclaimed, usually:
Explicitly, e.g. using an instance of Unchecked_Deallocation
.
Implicitly, e.g. using a controlled type derived from Finalization
; as noted here, when the scope of a controlled instance exits, automatic finalization calls Finalize
, which reclaims storage in a manner suitable to the type's design.
The children of Ada.Containers
use controlled types internally to encapsulate access values and manage memory automatically. For reference, compare your compiler's implementation of a particular container to the corresponding functional container cited here.
Ada offers a variety of ways to manage memory, summarized on slide 28 in the author's order of preferability:
In the particular case of Main
, the program allocates storage for 16 instances of Integer
. As noted on slide 12, "A compiler may reclaim allocated memory when the corresponding access type goes out of scope." For example, a recent version of the GNAT reference manual indicates that the following storage management implementation advice is followed:
A storage pool for an anonymous access type should be created at the point of an allocator for the type, and be reclaimed when the designated object becomes inaccessible.
Absent such an indication, the storage is not required to be reclaimed. It is typically reclaimed by the host operating system when the program exits.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With