Checking if your Delphi application leaks memory
Posted: (EET/GMT+2)
In 32-bit Windows environments, the operating system does "garbage collection" -- closes open files, frees allocated memory and so on when your application terminates. Also, if you know Java, this might be a familar concept to you. So, you might think: because the OS frees my memory, I don't have to worry about freeing it myself.
Basically, this is true, and if your application allocates only a little bits of memory, this might be an appropriate solution. However, creating "leaky" applications shows something about you as a programmer: you don't care to keep your own environment clean. Besides, if your application needs to run in tight memory conditions and/or requires large amounts of memory, you really want to make sure your application frees all the memory it has allocated.
In Delphi, there are many ways to allocate memory. The most common ways are to use New or GetMem procedures, but AllocMem and StrAlloc can also be used. While these methods allow you to explicitly allocate memory, Delphi applications also allocate memory "behind the scenes". For example, when you create a new object instance or use a long string, memory is allocated.
The key to checking if your application leaks memory is the routine GetHeapStatus, which is defined in the System unit. This routine returns a THeapStatus structure, which has a field called TotalAllocated. This field is incremented whenever memory is allocated, either implicitly or explicitly, and decremented when memory is freed.
Thus, if you save the value in the beginning of your application, and then the second time when your application ends, the difference of these values tells you how much memory your application leaks.
However, you cannot simply save the state of the allocated memory in a form's OnCreate event for example. This is because memory allocation has already taken place, for example by the Classes unit's initialization section and your form of course. Instead, we must make sure no prior allocations have been done. For this reason, we must save the state in a initialization section of an unit.
I've written an very simple unit, called MemCheck. It is indeed very simple: it automatically calculates how much memory your application leaks, and if it leaks, it displays a message box telling you how much.
The unit's finalization sections looks like this:
Var
Leak : Integer;
Initialization
Finalization
HeapStatus := GetHeapStatus;
Leak := HeapStatus.TotalAllocated-VCLLeak;
If (Leak > 0) Then Begin
MessageBox(0,PChar('Your application leaks '+IntToStr(Leak)+' bytes.'),
'Memory Leak',mb_OK or mb_IconExclamation);
End;
End.
When your application terminates, this finalization section is called. For this to work properly, the unit must be the first unit listed in your projects main source file. For example:
program MemLeak;
uses
MemCheck,
MainForm in 'MainForm.pas' {Form1},
...
Back to the above finalization section, notice the substraction of the VCLLeak constant. While writing this unit, I found that the Delphi VCL routines leak 1220 bytes of memory, no matter how simple your app is (also, I found that the ShowMessage routine will leak 16 bytes the first time it is called). Note that the unit, in its present state, only works with normal VCL (form based) applications. If you aren't using forms, set the VCLLeak constant to zero and recompile.
With this simple unit, you can check very easily if your application leaks memory. If you get no warnings when your program ends, you can be sure that your app won't leak any memory (except the 1220 bytes if you are using forms). However, if you are using the Win32 API memory management routines like VirtualAlloc, this unit won't help you.
I've also written two very simple routines, SaveAllocationState and RestoreAllocation state, which allow you to check if a (possibly recursive) routine leaks memory. I won't describe here how to use these routines: see the example code instead.
Anyway, I hope this unit will help you write more "memoryproof" programs. Happy hacking!