RAD Studio VCL Reference
ContentsIndex
PreviousUpNext
System::TMemoryManagerEx Record

System::TMemoryManagerEx defines extended memory block entry points.

Pascal
TMemoryManagerEx = record
  GetMem: function(Size: Integer): Pointer;
  FreeMem: function(P: Pointer): Integer;
  ReallocMem: function(P: Pointer; Size: Integer): Pointer;
  AllocMem: function(Size: Cardinal): Pointer;
  RegisterExpectedMemoryLeak: function(P: Pointer): Boolean;
  UnregisterExpectedMemoryLeak: function(P: Pointer): Boolean;
end;
C++
struct TMemoryManagerEx {
  function(Size: Integer): Pointer GetMem;
  function(P: Pointer): Integer FreeMem;
  function(P: Pointer; Size: Integer): Pointer ReallocMem;
  function(Size: Cardinal): Pointer AllocMem;
  function(P: Pointer): Boolean RegisterExpectedMemoryLeak;
  function(P: Pointer): Boolean UnregisterExpectedMemoryLeak;
};

The RegisterExpectedMemoryLeak type is used by the GetMemoryManager and SetMemoryManager procedures. It defines the routines that allocate and free memory.  

The GetMem field (Delphi) or method (C++) must specify a function that allocates the given number of bytes and returns a pointer to the newly allocated block, as invoked by the GetMemory routine.  

The Size parameter passed to the GetMem function will never be zero. If the GetMem function cannot allocate a block of the given size, it should return nil (Delphi) or NULL (C++).  

The FreeMem field (Delphi) or method (C++) must specify a function that deallocates the given block. The pointer parameter passed to the FreeMem function will never be nil (Delphi) or NULL (C++). If the FreeMem function successfully deallocates the given block, it should return zero. Otherwise, it should return a non-zero value. As invoked by the FreeMemory routine.  

The ReallocMem field (Delphi) or method (C++) must specify a function that reallocates the given block to the given new size. The pointer parameter passed to the ReallocMem function will never be nil (Delphi) or NULL (C++), and the Size parameter will never be zero. The ReallocMem function must reallocate the given block to the given new size, possibly moving the block if it cannot be resized in place. Any existing contents of the block must be preserved, but newly allocated space can be uninitialized. The ReallocMem function must return a pointer to the reallocated block, or nil (Delphi) or NULL (C++) if the block cannot be reallocated. As invoked by the ReallocMem routine.  

The AllocMem field (Delphi) or method (C++) must specify a function that allocates the given number of bytes and returns a pointer to the newly allocated block, as invoked by the AllocMem routine.  

The RegisterExpectedMemoryLeak field (Delphi) or method (C++) must specify a function that registers a memory location that an application has allocated and does not expect to free, as invoked by the RegisterExpectedMemoryLeak routine.  

The UnregisterExpectedMemoryLeak field (Delphi) or method (C++) must specify a function that removes a memory location from the Memory Manager's list of expected memory leaks, as invoked by the UnregisterExpectedMemoryLeak routine.  

C++ Examples: 

 

/*
This example demonstrates the use of SetMemoryManager and
GetMemoryManager routines. Note that this example is
thread safe.
*/

bool isMyMemMgr;
TMemoryManagerEx oldMemMgr;
volatile long getMemCalls;
volatile long freeMemCalls;
volatile long reallocMemCalls;
volatile long allocMemCalls;

void* __fastcall myGetMem(int size)
{
    //safely increment the counter
    InterlockedIncrement(&getMemCalls);

    //route the call
    return oldMemMgr.GetMem(size);
}

int __fastcall myFreeMem(void* p)
{
    //safely increment the counter
    InterlockedIncrement(&freeMemCalls);

    //route the call
    return oldMemMgr.FreeMem(p);
}

void* __fastcall myReallocMem(void* p, int size)
{
    //safely increment the counter
    InterlockedIncrement(&reallocMemCalls);

    //route the call
    return oldMemMgr.ReallocMem(p, size);
}

void* __fastcall myAllocMem(int size)
{
    //safely increment the counter
    InterlockedIncrement(&allocMemCalls);

    //route the call
    return oldMemMgr.AllocMem(size);
}

void __fastcall TForm3::btUseSysMemMgrClick(TObject *Sender)
{
    //switch button states
    btUseSysMemMgr->Enabled = false;
    btUseMyMemMgr->Enabled = true;

    //set the old memory manager back
    SetMemoryManager(oldMemMgr);

    isMyMemMgr = false;

    //clear out the variables
    getMemCalls     = 0;
    freeMemCalls    = 0;
    reallocMemCalls = 0;
    allocMemCalls   = 0;
}

void __fastcall TForm3::FormDestroy(TObject *Sender)
{
    //set the old memory manager back
    if (isMyMemMgr)
    {
        SetMemoryManager(oldMemMgr);
    }
}

void __fastcall TForm3::Timer1Timer(TObject *Sender)
{
    //Note that IntToStr calls will also Allocate/Free
    //memory so at each timer tick the counts will be +4;

    Form3->edGetMem->Text = IntToStr((int)getMemCalls);
    Form3->edFreeMem->Text = IntToStr((int)freeMemCalls);
    Form3->edReallocMem->Text = IntToStr((int)reallocMemCalls);
    Form3->edAllocMem->Text = IntToStr((int)allocMemCalls);
}

void __fastcall TForm3::btUseMyMemMgrClick(TObject *Sender)
{
    TMemoryManagerEx myMemMgr;

    //switch button states
    btUseSysMemMgr->Enabled = true;
    btUseMyMemMgr->Enabled = false;

    //get the old memory manager
    GetMemoryManager(oldMemMgr);

    //create out instance
    myMemMgr.GetMem = myGetMem;
    myMemMgr.FreeMem = myFreeMem;
    myMemMgr.AllocMem = myAllocMem;
    myMemMgr.ReallocMem = myReallocMem;

    //use defaults for this - not important
    myMemMgr.RegisterExpectedMemoryLeak = oldMemMgr.RegisterExpectedMemoryLeak;
    myMemMgr.UnregisterExpectedMemoryLeak = oldMemMgr.UnregisterExpectedMemoryLeak;

    //clear out the variables
    getMemCalls     = 0;
    freeMemCalls    = 0;
    reallocMemCalls = 0;
    allocMemCalls   = 0;

    //install the new memory manager
    SetMemoryManager(myMemMgr);

    isMyMemMgr = true;
}

void __fastcall TForm3::btDoSomethingClick(TObject *Sender)
{
    void *ptr;
    //perform some new and delete
    for (int i=0; i < 1000; ++i)
    {
        ptr = GetMemory(4);
        FreeMemory(ptr);
    }
}

 

Delphi Examples: 

{
This example demonstrates the use of SetMemoryManager and
GetMemoryManager routines. Note that this example is
thread safe.
}
var
  OldMemMgr       : TMemoryManagerEx;
  GetMemCalls     : Integer;
  FreeMemCalls    : Integer;
  ReallocMemCalls : Integer;
  AllocMemCalls   : Integer;

function MyGetMem(Size: Integer): Pointer;
begin
  { Route the call }
  Result := OldMemMgr.GetMem(Size);

  { Safely increment the counter }
  InterlockedIncrement(GetMemCalls);
end;

function MyFreeMem(P: Pointer): Integer;
begin
  { Route the call }
  Result := OldMemMgr.FreeMem(P);

  { Safely increment the counter }
  InterlockedIncrement(FreeMemCalls);
end;

function MyReallocMem(P: Pointer; Size: Integer): Pointer;
begin
  { Route the call }
  Result := OldMemMgr.ReallocMem(P, Size);

  { Safely increment the counter }
  InterlockedIncrement(ReallocMemCalls);
end;

function MyAllocMem(Size: Cardinal): Pointer;
begin
  { Route the call }
  Result := OldMemMgr.AllocMem(Size);

  { Safely increment the counter }
  InterlockedIncrement(AllocMemCalls);
end;

procedure TForm2.btPerformSomethingClick(Sender: TObject);
var
  X : Integer;
  I : ^Integer;
begin
  { Perform some allocations and frees }
  for X := 0 to 999 do
  begin
    New(I);
    Dispose(I);
  end;
end;

procedure TForm2.btUseMyMemMgrClick(Sender: TObject);
var
  MyMemMgr : TMemoryManagerEx;
begin
  { Switch button states }
  btUseSystemMemMgr.Enabled := true;
  btUseMyMemMgr.Enabled := false;

  { Get the old memory manager }
  GetMemoryManager(OldMemMgr);

  { Create our instance }
  MyMemMgr.GetMem := MyGetMem;
  MyMemMgr.FreeMem := MyFreeMem;
  MyMemMgr.ReallocMem := MyReallocMem;
  MyMemMgr.AllocMem := MyAllocMem;

  { Use the defaults for this - not important }
  MyMemMgr.RegisterExpectedMemoryLeak := OldMemMgr.RegisterExpectedMemoryLeak;
  MyMemMgr.UnregisterExpectedMemoryLeak := OldMemMgr.UnregisterExpectedMemoryLeak;

  { Clear out the count variables }
  GetMemCalls := 0;
  FreeMemCalls := 0;
  ReallocMemCalls := 0;
  AllocMemCalls := 0;

  { Install the new memory manager }
  SetMemoryManager(MyMemMgr);
end;

procedure TForm2.btUseSystemMemMgrClick(Sender: TObject);
begin
  { Switch button states }
  btUseSystemMemMgr.Enabled := false;
  btUseMyMemMgr.Enabled := true;

  { Set the old memory manager back! }
  SetMemoryManager(OldMemMgr);

  GetMemCalls := 0;
  FreeMemCalls := 0;
  ReallocMemCalls := 0;
  AllocMemCalls := 0;
end;

procedure TForm2.FormDestroy(Sender: TObject);
begin
  { Set the old memory manager back }
  if IsMemoryManagerSet then
     SetMemoryManager(OldMemMgr);
end;

procedure TForm2.Timer1Timer(Sender: TObject);
begin
  {
  Note that IntToStr calls will also Allocate/Free
  memory so at each timer tick the counts will be increased;
  }
  Form2.edtGetMemCalls.Text := IntToStr(GetMemCalls);
  Form2.edtFreeMemCalls.Text := IntToStr(FreeMemCalls);
  Form2.edtReallocMemCalls.Text := IntToStr(ReallocMemCalls);
  Form2.edtAllocMemCalls.Text := IntToStr(AllocMemCalls);
end;

 

Copyright(C) 2009 Embarcadero Technologies, Inc. All Rights Reserved.
What do you think about this topic? Send feedback!