[prev] [prev-tail] [tail] [up]

#### Writing your own memory manager

Free Pascal allows you to write and use your own memory manager. The standard functions GetMem, FreeMem, ReallocMem and Maxavail use a special record in the system unit to do the actual memory management. The system unit initializes this record with the system unit’s own memory manager, but you can read and set this record using the GetMemoryManager and SetMemoryManager calls:

     procedure GetMemoryManager(var MemMgr: TMemoryManager);
     procedure SetMemoryManager(const MemMgr: TMemoryManager);

the TMemoryManager record is defined as follows:

       TMemoryManager = record
         Getmem      : Function(Size:Longint):Pointer;
         Freemem     : Function(var p:pointer):Longint;
         FreememSize : Function(var p:pointer;Size:Longint):Longint;
         AllocMem    : Function(Size:longint):Pointer;
         ReAllocMem  : Function(var p:pointer;Size:longint):Pointer;
         MemSize     : function(p:pointer):Longint;
         MemAvail    : Function:Longint;
         MaxAvail    : Function:Longint;
         HeapSize    : Function:Longint;
       end;

As you can see, the elements of this record are procedural variables. The system unit does nothing but call these various variables when you allocate or deallocate memory.

Each of these functions corresponds to the corresponding call in the system unit. We’ll describe each one of them:

Getmem
  This function allocates a new block on the heap. The block should be Size bytes long. The return value is a pointer to the newly allocated block.
Freemem
  should release a previously allocated block. The pointer P points to a previously allocated block. The Memory manager should implement a mechanism to determine what the size of the memory block is 3 The return value is optional, and can be used to return the size of the freed memory.
FreememSize
  This function should release the memory pointed to by P. The argument Size is the expected size of the memory block pointed to by P. This should be disregarded, but can be used to check the behaviour of the program.
AllocMem
  Is the same as getmem, only the allocated memory should be filled with zeroes before the call returns.
ReAllocMem
  Should allocate a memory block Size bytes large, and should fill it with the contents of the memory block pointed to by P, truncating this to the new size of needed. After that, the memory pointed to by P may be deallocated. The return value is a pointer to the new memory block. Note that P may be Nil, in which case the behaviour is equivalent to GetMem.
MemSize
  should return the total amount of memory available for allocation. This function may return zero if the memory manager does not allow to determine this information.
MaxAvail
  should return the size of the largest block of memory that is still available for allocation. This function may return zero if the memory manager does not allow to determine this information.
HeapSize
  should return the total size of the heap. This may be zero is the memory manager does not allow to determine this information.

To implement your own memory manager, it is sufficient to construct such a record and to issue a call to SetMemoryManager.

To avoid conflicts with the system memory manager, setting the memory manager should happen as soon as possible in the initialization of your program, i.e. before any call to getmem is processed.

This means in practice that the unit implementing the memory manager should be the first in the uses clause of your program or library, since it will then be initialized before all other units (except of the system unit)

This also means that it is not possible to use the heaptrc unit in combination with a custom memory manager, since the heaptrc unit uses the system memory manager to do all it’s allocation. Putting the heaptrc unit after the unit implementing the memory manager would overwrite the memory manager record installed by the custom memory manager, and vice versa.

The following unit shows a straightforward implementation of a custom memory manager using the memory manager of the C library. It is distributed as a package with Free Pascal.

     unit cmem;

     {$mode objfpc}

     interface

     Function Malloc (Size : Longint) : Pointer;cdecl;
       external 'c' name 'malloc';
     Procedure Free (P : pointer); cdecl; external 'c' name 'free';
     Procedure FreeMem (P : Pointer); cdecl; external 'c' name 'free';
     function ReAlloc (P : Pointer; Size : longint) : pointer; cdecl;
       external 'c' name 'realloc';
     Function CAlloc (unitSize,UnitCount : Longint) : pointer;cdecl;
       external 'c' name 'calloc';

     implementation

     Function CGetMem  (Size : Longint) : Pointer;

     begin
       result:=Malloc(Size);
     end;

     Function CFreeMem (Var P : pointer) : Longint;

     begin
       Free(P);
       Result:=0;
     end;

     Function CFreeMemSize(var p:pointer;Size:Longint):Longint;

     begin
       Result:=CFreeMem(P);
     end;

     Function CAllocMem(Size : Longint) : Pointer;

     begin
       Result:=calloc(Size,1);
     end;

     Function CReAllocMem (var p:pointer;Size:longint):Pointer;

     begin
       Result:=realloc(p,size);
     end;

     Function CMemSize (p:pointer): Longint;

     begin
       Result:=0;
     end;

     Function CMemAvail : Longint;

     begin
       Result:=0;
     end;

     Function CMaxAvail: Longint;

     begin
       Result:=0;
     end;

     Function CHeapSize : Longint;

     begin
       Result:=0;
     end;

     Const
      CMemoryManager : TMemoryManager =
         (
           GetMem : CGetmem;
           FreeMem : CFreeMem;
           FreememSize : CFreememSize;
           AllocMem : CAllocMem;
           ReallocMem : CReAllocMem;
           MemSize : CMemSize;
           MemAvail : CMemAvail;
           MaxAvail : MaxAvail;
           HeapSize : CHeapSize;
         );

     Var
       OldMemoryManager : TMemoryManager;

     Initialization
       GetMemoryManager (OldMemoryManager);
       SetMemoryManager (CmemoryManager);

     Finalization
       SetMemoryManager (OldMemoryManager);
     end.

[prev] [prev-tail] [front] [up]