Memory Management with Storage Pools


Memory management can cause real headache due to memory leakage over 
time. That is, memory allocation is not properly deallocated after the 
call. When the memory runs out, the result could be catastrophic for 
some applications. This problem can be recued by garbage collector 
built-in the compiler such as Java. However, the cost of run-time 
overhead is high.
     
Here comes Ada 95 to the recue. How is it possible you may ask? Ah! 
Ada 95 provides a feature called Storage Pool. It allows the users 
have total control over the memory management. Best of all, it does 
not involve run-time overhead as garbage collector. When it is 
combined with controlled type, the memory leakage problem is history.
    
As shown in the test case, 100 storage elements were allocated 
initially. Then, these storage elements are reused again and again. It 
is pretty cool isn't it? Enjoy.
     
----------------------------------------
     
     with System.Storage_Pools;
     with System.Storage_Elements;
     
     package Memory_Management is
     
        use System;
     
        type User_Pool (Size : Storage_Elements.Storage_Count) is new
           System.Storage_Pools.Root_Storage_Pool with private;
     
        procedure Allocate (
           Pool            : in out User_Pool;
           Storage_Address :    out System.Address;
           Size_In_Storage_Elements : in Storage_Elements.Storage_Count;
           Alignment       : in Storage_Elements.Storage_Count);
     
        procedure Deallocate (
           Pool            : in out User_Pool;
           Storage_Address : in     System.Address;
           Size_In_Storage_Elements : in Storage_Elements.Storage_Count;
           Alignment       : in Storage_Elements.Storage_Count);
     
        function Storage_Size (Pool : in User_Pool)
           return Storage_Elements.Storage_Count;
     
        -- Exeption declaration
        Memory_Exhausted : exception;
     
        Item_Too_Big : exception;
     
     private
        type User_Pool (Size : Storage_Elements.Storage_Count) is new
           System.Storage_Pools.Root_Storage_Pool with record
           Data       : Storage_Elements.Storage_Array (1 .. Size);
           Addr_Index : Storage_Elements.Storage_Count := 1;
        end record;
     
     end Memory_Management;
     
     with Ada.Exceptions;
     with Ada.Text_Io;
     with System.Storage_Elements;
     with System.Address_To_Access_Conversions;
     
     package body Memory_Management is
     
        use Ada;
        use Text_Io;
        use type System.Storage_Elements.Storage_Count;
     
        Package_Name : constant String := "Memory_Management.";
     
        -- Used to turn on/off the debug information
        Debug_On : Boolean := False;
     
        type Holder is record
           Next_Address : System.Address := System.Null_Address;
        end record;
     
        package Addr_To_Acc is new Address_To_Access_Conversions (Holder);
     
        -- Keep track of the size of memory block for reuse
        Free_Storage_Keeper : array (Storage_Elements.Storage_Count range 1 
     .. 100)
          of System.Address := (others => System.Null_Address);
     
        procedure Display_Info (Message : string; With_New_Line : Boolean 
     := True) is
        begin
           if Debug_On then
              if With_New_Line then
                 Put_Line (Message);
              else
                 Put (Message);
              end if;
           end if;
        end Display_Info;
     
        procedure Allocate (
              Pool            : in out User_Pool;
              Storage_Address :    out System.Address;
              Size_In_Storage_Elements : in Storage_Elements.Storage_Count;
              Alignment       : in Storage_Elements.Storage_Count) is
     
           Procedure_Name : constant String := "Allocate";
           Temp_Address : System.Address := System.Null_Address;
           Marker : Storage_Elements.Storage_Count;
        begin
     
           Marker := (Size_In_Storage_Elements + Alignment - 1) / 
     Alignment;
     
           if Free_Storage_Keeper (Marker) /= System.Null_Address then
              Storage_Address := Free_Storage_Keeper (Marker);
              Free_Storage_Keeper (Marker) :=
                Addr_To_Acc.To_Pointer (Free_Storage_Keeper 
     (Marker)).Next_Address;
           else
              Temp_Address := Pool.Data (Pool.Addr_Index)'Address;
              
              Pool.Addr_Index := Pool.Addr_Index + Alignment *
                          ((Size_In_Storage_Elements + Alignment - 1) / 
     Alignment);
     
              -- make sure memory is available as requested
              if Pool.Addr_Index > Pool.Size then
                 Exceptions.Raise_Exception (Storage_Error'Identity,
                    "Storage exhausted in " & Package_Name & 
     Procedure_Name);
              else
                 Storage_Address := Temp_Address;
              end if;
           end if;
     
           Display_Info  ("Address allocated from pool: " &
             System.Storage_Elements.Integer_Address'Image (
                                  System.Storage_Elements.To_Integer 
     (Storage_Address)));
     
           Display_Info ("storage elements allocated from pool: " &
              System.Storage_Elements.Storage_Count'Image 
     (Size_In_Storage_Elements));
     
           Display_Info ("Alignment in allocation operation: " &
              System.Storage_Elements.Storage_Count'Image (Alignment));
     
        exception
           when Error : others => -- Object too big or memory exhausted
              Display_Info (Exceptions.Exception_Information (Error));
              raise;
     
        end Allocate;
     
        procedure Deallocate (
              Pool            : in out User_Pool;
              Storage_Address : in     System.Address;
              Size_In_Storage_Elements : in Storage_Elements.Storage_Count;
              Alignment       : in Storage_Elements.Storage_Count) is
     
           Marker : Storage_Elements.Storage_Count;
     
        begin
     
           Marker := (Size_In_Storage_Elements + Alignment - 1) / 
     Alignment;
           Addr_To_Acc.To_Pointer (Storage_Address).Next_Address :=
                                              Free_Storage_Keeper (Marker);
           Free_Storage_Keeper (Marker) := Storage_Address;
     
           Display_Info  ("Address returned to pool: " &
             System.Storage_Elements.Integer_Address'Image (
                                  System.Storage_Elements.To_Integer 
     (Storage_Address)));
     
           Display_Info ("storage elements returned to pool: " &
              System.Storage_Elements.Storage_Count'Image 
     (Size_In_Storage_Elements));
     
           Display_Info ("Alignment used in deallocation: " &
              System.Storage_Elements.Storage_Count'Image (Alignment));
     
        end Deallocate;
     
        function Storage_Size (Pool : in User_Pool)
              return Storage_Elements.Storage_Count is
        begin
           return Pool.Size;
        end Storage_Size;
     
     begin
     
        null;
     
     end Memory_Management;
     
     with Ada.Finalization;
     
     package Memory_Management.Support is
     
        use Ada;
     
        -- Adjust the storage size according to the application
        Big_Pool : User_Pool (Size => 100);
     
        type Int_Acc is access Integer;
        for Int_Acc'Storage_Pool use Big_Pool;
     
        type Str_Acc is access all String;
        for Str_Acc'Storage_Pool use Int_Acc'Storage_Pool;
     
        type General_Data is new Finalization.Controlled with record
           Id : Int_Acc;
           Name : Str_Acc;
        end record;
     
        procedure Initialize (Object : in out General_Data);
     
        procedure Finalize (Object : in out General_Data);
     
     end Memory_Management.Support;
     
     
        
     with Ada.Unchecked_Deallocation;
     
     package body Memory_Management.Support is
     
        procedure Free is new Ada.Unchecked_Deallocation (Integer, Int_Acc);
        procedure Free is new Ada.Unchecked_Deallocation (String, Str_Acc);
     
        procedure Initialize (Object : in out General_Data) is
        begin
           null;
        end Initialize;
     
        procedure Finalize (Object : in out General_Data) is
        begin
           Free (Object.Id);
           Free (Object.Name);
        end Finalize;
     
     end Memory_Management.Support;
     
     with Ada.Finalization;
     with Ada.Text_Io;
     with Memory_Management.Support;
     
     procedure Memory_Management.Test is
        use Ada;
        use Text_Io;
     
     begin
     
        Put_Line ("********* Memory Control Testing Starts **********");
     
        for Index in 1 .. 10 loop
           declare
              David_Botton : Support.General_Data;
              Nick_Roberts : Support.General_Data;
              Anh_Vo : Support.General_Data;
     
           begin
              David_Botton := (Finalization.Controlled with
                 Id => new Integer' (111), Name => new String' ("David 
     Botton"));
              Nick_Roberts := (Finalization.Controlled with
                 Id => new Integer' (222), Name => new String' ("Nick 
     Roberts"));
              Anh_Vo := (Finalization.Controlled with
                 Id => new Integer' (333), Name => new String' ("Anh Vo"));
           end;
        end loop;
     
        Put_Line ("Memory Management Test Passes");
     
     exception
        when others =>
           Put_Line ("Memory Management Test Fails");
     
     end Memory_Management.Test;



Contributed by: Anh Vo
Contributed on: May 17, 1999
License: Public Domain

Back