Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Why use FreeMem/Dispose routines to release memory, but there is no memory reduces?

Tags:

memory

delphi

I use AllocMem/GetMem/New routines to allocate memory, then use FreeMem/Dispose routines to release memory. But I found(by Process Explorer) that memory size of the process not reduced.

If I use GlobalAllocPtr/HeapAlloc and GlobalFreePtr/HeapFree APIs, the memory size will reduced.

Here is my test code:

type
  TMyRec = record
    Name: string;
    TickCount: Cardinal;
    Buf: array[0..1024 - 1] of byte;
  end;
  PMyRec = ^TMyRec;

var
  Form1: TForm1;

implementation

{$R *.dfm}

procedure TForm1.FormDestroy(Sender: TObject);
begin
  FList.Free;
end;

procedure TForm1.FormCreate(Sender: TObject);
begin
  FList := TList.Create;
  ReportMemoryLeaksOnShutdown := true;
end;

procedure TForm1.Button1Click(Sender: TObject);
var
  i: Integer;
  Size: Integer;
  Rec: PMyRec;
  Heap: Cardinal;
begin
  Size := SizeOf(TMyRec);
  Heap := GetProcessHeap;
  for I := 0 to 2000 - 1 do
  begin
    Rec := AllocMem(Size);                              // Delphi routine
    //GetMem(Rec, Size);                                // Delphi routine
    //New(Rec);                                         // Delphi routine

    //Rec := GlobalAllocPtr(GPTR, Size);                // Windows API
    //Rec := HeapAlloc(Heap, HEAP_ZERO_MEMORY, Size);   // Windows API
    FList.Add(Rec);
  end;
end;

procedure TForm1.Button2Click(Sender: TObject);
var
  i: Integer;
  Size: Integer;
  Rec: PMyRec;
  Heap: Cardinal;
begin
  Size := SizeOf(TMyRec);
  Heap := GetProcessHeap;
  for i := FList.Count - 1 downto 0 do
  begin
    Rec := PMyRec(FList.Items[i]);
    FreeMem(Rec, Size);            // Delphi routine
    //Dispose(Rec);                // Delphi routine

    //GlobalFreePtr(Rec);          // Windows API
    //HeapFree(Heap, 0, Rec);      // Windows API
  end;
  FList.Clear;
end;
like image 433
Leo Avatar asked Apr 03 '11 14:04

Leo


2 Answers

That is how Delphi memory manager works - it supports it's own memory cache so that it does not return every freed memory back to system, but holds it in the cache. Next time then it allocates a memory it tries first to find the requested memory in the cache, not in system. That makes memory allocation/deallocation faster.

BTW never use FreeMem for records with lifetime managed fields (ex strings, as in your example) - it leads to memory leaks. Use Dispose instead.

Also never use GetMem for records with lifetime managed fields (commented line in your example) - it leads to access violations. Use New.

like image 67
kludg Avatar answered Sep 17 '22 08:09

kludg


You're seeing this because getting memory from Windows is an expensive operation, so when you use Delphi's built in memory manager, it caches a certain amount of unused memory since you're likely to need it again for something else soon.

If you free a lot of memory you'll probably see it give some back to the operating system, but it still keeps some of it around locally so it won't have to ask for more as soon.

like image 31
Mason Wheeler Avatar answered Sep 21 '22 08:09

Mason Wheeler