memory management with ada 2012 - ku leuvendirk.craeynest/ada... · fosdem 2016 3 some definitions...
TRANSCRIPT
2FOSDEM 2016
Outline
When you don't need it
Access Types in Ada
Managing Memory
Conclusion
3FOSDEM 2016
Some Definitions
Global (permanent) variables are at fixed memory locationsAda : Variables declared in library packagesPermanent lifetime, never released
Local variables (of subprograms) are allocated on a stackAKA automatic variablesAda : variables of subprograms (and tasks)Automatically released when subprogram exitsRequired for recursivity and multi-tasking
Dynamic variables are allocated on a heap (pool)Ada : variables created by allocators – newHave to be released by someone, sometime (manually,
automatically when not used any more...)
4FOSDEM 2016
When you don't need it
5FOSDEM 2016
Dynamic Stack Variables
Ada allows stack variables of statically-unknown size
Size given by initial value:
type Vector is array (Positive range <>) of Length;begin
loopGet (N);exit when N=0;declare
Dyn_Array : Vector (1 .. N); -- N statically unknownbegin
Dyn_Array := (others => 0.0); -- No restriction on usage…
end;end loop;
end;
Buffer : constant String := Get_Value_From_Network; -- No overflow possible!
6FOSDEM 2016
Containers
Containers are useful for most usagesUse pointers internally, nothing visible outsideMemory management is fully controlled, no leak
✔ We'll see later how…
Inspired by the STLVectorsMapsDoubly linked listsMutliway treesSets ...
7FOSDEM 2016
Access Types In Ada
8FOSDEM 2016
Access (?) Types in Ada
Access types provide indirect access to variables and subprogramsOK, they are pointersAn access type is not an address
SyntaxPool specific
Generalized access to variable
Generalized access to constant
type Name is [not null] access Designated_Type;
type Name is [not null] access all Designated_Type;
type Name is [not null] access constant Designated_Type;
Really a pointer with read-only rights
9FOSDEM 2016
Basic usage
The null value designates nothingAutomatic initialization
✔ All access objects are initialized to null
Dereference is checked✔ Dereferencing null Exception Constraint_Error
If type defined as not null:✔ Null value not allowed, all pointers must be initialized
AllocatorsSimple allocator (uninitialized)
Initialized allocator
P := new Date; – Equivalent to: V: Date;
P := new Date'(D); -- Equivalent to: V: Date := D;
10FOSDEM 2016
Dereference
Explicit: .all, implicit when no ambiguity
User defined implicit dereference
type Major is (Letters, Sciences, Technology);type Student_Record (With_Major : Major) is
recordMathematics : Grade;case With_Major is
when Sciences => Physics : Grade;…
end case;end record;
type Student_Record_Ptr is access Student_Record;PSR1: Student_Record_Ptr;PSR2: Student_Record_Ptr;
beginPSR2 := new Student_Record (Sciences); -- No init, constraint must be givenPSR2.Physics := B; -- Equivalent to PSR.all.Physics := B;PSR1.all := PSR2.all
end;
11FOSDEM 2016
Managing Memory
12FOSDEM 2016
Issues
Allocated space must be returned when not used any moreA compiler may reclaim allocated memory when the
corresponding access type goes out of scope.
Returning all variables when they are not used any more does not guarantee the absence of memory shortage, due to fragmentation
Standard allocation/dealloction algorithm is usually part of the OS/Run-TimeEscapes validation, no user control
Standard allocation algorithm may be incompatible with real-time:Global lockBest fit / First fit often have unbounded WCET
13FOSDEM 2016
Releasing Memory Space
The language provides:
A specific function must be instantiated for each access type:
Makes it easy to identify modules where memory is deallocated
generictype Object (<>) is limited private;type Name is access Object;
procedure Ada.Unchecked_Deallocation (X : in out Name);
type Link is access Node ;procedure Free is new Ada.Unchecked_Deallocation (Node, Link);
P : Link;...Free(P); -- Memory space designated by P is freed, and P is reset to null
14FOSDEM 2016
Controlled Types (1)
A type whose initialization, finalization and assignment are under program's control.A controlled type is a descendant of Controlled or
Limited_Controlled:
Default procedures do nothing✔ Only those that need special processing need to be redefined
package Ada.Finalization istype Controlled is abstract tagged private;procedure Initialize (Object : in out Controlled);procedure Adjust (Object : in out Controlled);procedure Finalize (Object : in out Controlled);
type Limited_Controlled is abstract tagged limited private;procedure Initialize (Object : in out Limited_Controlled);procedure Finalize (Object : in out Limited_Controlled);
end Ada.Finalization;
15FOSDEM 2016
Controlled Types (2)
InitializationThe procedure is called after assignment of default values.
FinalizationApplied in reverse order from initialization.
AssignmentLHS := RHS
✔ The LHS is finalized✔ Bit copy of RHS into LHS✔ Adjust is called on (new) LHS
Very convenient to hide pointers and memory management
To be honnest: it's slightly more complicated than that
(optional anonymous temporary)
16FOSDEM 2016
Use of Controlled Types to Hide Access Types
Example: Unbounded_StringAn unbounded string is just a (controlled) pointer to String:
Old textA
B New text
New text 1) A is finalized
3) A is adjusted
2) Bit copy
type Unbouded_String is new Ada.Finalization.Controlled withrecord
Content : String_Access;end record;
procedure Adjust (Object : in out Unbounded_String);procedure Finalize (Object : in out Unbounded_String);
A := B
17FOSDEM 2016
Collection
Memory space reserved for exclusive use by a given access type (and types derived from it).Reserved beforehandDoes not compete with other access types.
Specification of the size of a collectionNon static clause:
Reserves at least the given space (or Storage_Error is raised)
Exclusive of Storage_PoolRequires storage to be freed when the
scope of the type is left
Accessing the size of a collectionAttribute: Access_type'Storage_Size
for Ptr_T'STORAGE_SIZE use n;
Used by Ptr_T
Used by other access types
18FOSDEM 2016
Null Storage_Size
Storage_Size can be anything, including 0
Special case : when Storage_Size is specified to be 0:Allocators (new) and Unchecked_Deallocation are not allowedPointers are only allowed to global or stack objects
Global/StackHeap
Pool specific GeneralGeneral General with null Storage_Size
19FOSDEM 2016
Pools (1)
A pool type is a type derived from Root_Storage_Poolwith Ada.Finalization;with System.Storage_Elements;package System.Storage_Pools is
pragma Preelaborate (System.Storage_Pools);type Root_Storage_Pool is abstract new Ada.Finalization.Limited_Controlled with private;
procedure Allocate(Pool : in out Root_Storage_Pool; Storage_address: out Address; Size_in_storage_elements: in Storage_Elements.Storage_Count; Alignment : in Storage_Elements.Storage_Count) is abstract;
procedure Deallocate(Pool : in out Storage_Pool; Storage_address : in Address; Size_in_storage_elements: in Storage_Elements.Storage_Count; Alignment : in Storage_Elements.Storage_Count) is abstract;
function Storage_size (Pool : Root_storage_pool)return Storage_elements.Storage_count is abstract;
private...
end System.Storage_pools;
A controlled type
20FOSDEM 2016
Pools (2)
How to manage dynamic allocation :Define policy
Declare one (or more) object(s):
Associate the object to an access type :
Properties:new gets memory by calling Allocate.Unchecked_Deallocation returns memory by calling Deallocate.T'Storage_size returns the result of calling Storage_SizeT'Storage_Pool designates the pool object associated with T
type Own_Pool is new System.Storage_pool.Root_Storage_Pool with ...;procedure Allocate ...;procedure Deallocate ...;function Storage_Size ...;
My_Pool : Own_Pool;
type T is access … with Storage_Pool => My_Pool;for T'Storage_Pool use My_Pool; -- Ada < 2012
21FOSDEM 2016
Pools (3)
Example: Fixed size allocatorAllocated size is limited to slot sizeFull slot reserved whatever the
allocated sizeDeallocation frees the whole slotOf course, it wastes space…
BenefitsAllocation, deallocation are O(1)No fragmentationSlot size can be parameterized:
type Fixed_Allocator (Slot_Size : Positive) isnew System.Storage_pool.Root_Storage_Pool;
22FOSDEM 2016
Default Storage Pool
The compiler provides a default storage pool for access types without associated storage pool.
The default storage pool can be specified:
The default pool can be null:
Forces Storage_Size to 0 (no allocator unless the type has user-defined storage pool)
pragma Default_Storage_Pool (Pool_Object);
pragma Default_Storage_Pool (null);
23FOSDEM 2016
Usages of Pools
Manage memory with a custom algorithmKnown space and timing properties, certified algorithm…
DebuggingGnat.Debug_Pools
✔ Trace allocations/deallocations✔ Display high-water marks, un-deallocated space at termination…
Persistent objects (even better with automatic dereference) J. Sparre Andersen, Ada-Europe 2010Kazakov components
24FOSDEM 2016
Subpools (1)
Some pools may manage subpoolsOf type Root_Storage_Pool_With_Subpools (derived from
Root_Storage_Pool)
A subpool is created with Create_SubpoolAn access type is associated with a pool (as before)An allocator may indicate a subpool:
✔ If no subpool is indicated, the default subpool is used (raises Program_Error by default)
A subpool can be reclaimed as a whole (with all its objects) by calling Deallocate_Subpool
Ptr := new (subpool) T;Ptr := new (subpool) T’(initial_value);
An indication of a "partition" of the space managed by the pool(whatever that means)
25FOSDEM 2016
Subpools (2)
UsageMark-release pool (example in Ada RM 13.11.6)
✔ "Mark" creates a new subpool✔ "Release" frees the subpool and makes the previous one active✔ Not allowed to use a subpool other than the top one
"families" of objects to be reclaimed together✔ Each subpool is a linked list of objects
managing multiple heaps✔ Embedded systems: allocations either from private or shared memory
...
26FOSDEM 2016
Conclusion
27FOSDEM 2016
Garbage Collection
Ada allows, but does not require garbage collection It's implemented with the JVM and .Net compilers
Pros:Great when you are unable to manage memory
✔ When everything is dynamically allocated and you are not able to manage when to deallocate
✔ When pointers evade to far-away locations, and nobody knows when to deallocate
✔ Not Ada !
Cons:Does not always work (circular dependencies)Does not avoid fragmentationUnpredictable execution time, unpredictable triggeringNot a silver bullet
✔ "Don't forget to return unused variables to null, or the GC won't get them"
28FOSDEM 2016
A Good Advice
Randy Bruckardt on comp.lang.ada, April 06, 2015
IMHO, the order of memory management preferability goes approximately as follows:
1) Stack-based (in Ada, this includes dynamically-sized objects, such as an array whose length depends on a parameter; this probably isn't implemented with a traditional stack, but the compiler will do the management).
2) Container-based. 3) Finalization-based. (Using a controlled wrapper of some sort;
deallocate on finalize. Smart pointers fall into this category. The only reason that these fall below 2) is that these are user-defined, meaning there is a higher possibility of errors. [Implementers make mistakes, but there are more people using there stuff so they don't last as long.])
4) Subpool-based. (Sometimes called "arenas"; this is a semi-automatic mechanism in that all items of a group are freed together.)
5) Manual allocate/deallocate (with or without storage pools).
29FOSDEM 2016
Ada Is Safer Because...
Pointers are initialized to null
Pointers preserve strong typingNo "void *"Enforces profile in pointers to subprograms
Dereference is checked for validity
Unchecked_Deallocation returns pointer to null
Explicit with of Ada.Unchecked_Deallocation makes sensitive modules stand out
Encapsulation prevents pointers from leaking everywhereWith containers, no visible pointer anywhere
Controlled types provide for automatic management
Pools and subpools for user controlled memory management
No garbage collection!
30FOSDEM 2016