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;
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
.
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.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With