Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Does Ada deallocate memory automatically under some circumstances?

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?

like image 873
GDI512 Avatar asked Dec 14 '22 07:12

GDI512


1 Answers

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:

  1. Stack-based.
  2. Container-based.
  3. Finalization-based.
  4. Subpool-based.
  5. Manual allocate/deallocate.

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.

like image 170
trashgod Avatar answered Apr 26 '23 05:04

trashgod