Title: How to find memory leaks
Question: What can you do if you know there is a resource or memory leak in your program ?
Answer:
Memory leaks are the black holes of programming, they
continuously swallow resources which will never be released
again. They can be a nightmare for a programmer: they
are hard to find, and exceptions or errors appear only
after a long time and usually not at the place of the
leak itself.
Contrary to Microsoft Dot Net, Delphi and the VCL have
no garbage collector. You have to care for the release
of each object yourself. It is for example easy to overlook
an object in a list which is not destroyed if the list is
released.
Possible error messages due to resource and memory leaks
are for example "The window does not have scroll bars"
(Microsoft Error Code 1447) and "Out of system resources".
What can you do if you know there is a resource or memory
leak ?
1. Control the memory usage with the task manager
2. Use tools like the freeware program "MemProof".
Other resource tracking tools are listed at
http://www.undu.com/Articles/980807c.html
3. Check your program for functions and objects which
have direct influence on memory: GetMem, FreeMem,
Constructors, Destructors (esp. of composed and list
objects), MapViewOfFile, etc.
4. Control the memory usage with API functions
GlobalMemoryStatus() and GetProcessMemoryInfo().
Use for example a debug symbol defined with
{$DEFINE DEBUG}, and show a few lables which
display the memory usage if this symbol is
defined:
{$IFDEF DEBUG}
TotalMemoryLabel.Visible:=true;
FreeMemoryLabel.Visible:=true;
ProcessMemoryLabel.Visible:=true;
MemoryLeakLabel.Visible:=true;
{$ENDIF}
procedure TForm.DebugProcessStatus(s : string);
var pmc: PPROCESS_MEMORY_COUNTERS;
cb: Integer;
MemStat: tMemoryStatus;
begin
MemStat.dwLength:=SizeOf(MemStat);
GlobalMemoryStatus(MemStat);
// Get the total and available system memory
TotalMemoryLabel.Caption := 'Total system memory: '+
FormatFloat('###,###',MemStat.dwTotalPhys/1024)+' KByte';
FreeMemoryLabel.Caption := 'Free physical memory: '+
FormatFloat('###,###',MemStat.dwAvailPhys/1024)+' KByte';
// Get the used memory for the current process
cb := SizeOf(TProcessMemoryCounters);
GetMem(pmc, cb);
pmc^.cb := cb;
if GetProcessMemoryInfo(GetCurrentProcess(), pmc, cb) then
begin
NewWorkingMemory:=Longint(pmc^.WorkingSetSize);
ProcessMemoryLabel.Caption := 'Process-Memory: '+
FormatFloat('###,###',NewWorkingMemory/1024)+' KByte';
MemoryLeakLabel.Caption := 'Memory Loss: '+
FormatFloat('###,###',(NewWorkingMemory-OldWorkingMemory)/1024)+' KByte';
OldWorkingMemory:=NewWorkingMemory;
end;
FreeMem(pmc);
DebugStatusLabel.caption:='Status: '+s;
end;