In order to prune out all of memory leaks I am trying to incorporate LeakCheck library into DUnit. The problem is that LeakCheck will report me memory leaks that are not true leaks. These are objects or other stuff allocated by RTL and destroyed on program exit.
LeakCheck contains a lot of handful routines that allow you to specify what to ignore and I was able to use them to ignore most of such "leaks". However, I don't know how to get rid one in particular:
program LeakCheckMemLeak;
{$APPTYPE CONSOLE}
uses
LeakCheck, TestFramework, LeakCheck.DUnit, LeakCheck.Utils, LeakCheck.Setup.Trace, System.SysUtils,
Forms, System.Classes;
{$R *.RES}
procedure LeakMemory;
var
LThread: TThread;
begin
LThread := TThread.Create(True);
LThread.Free;
end;
procedure DetectLeak;
var
Snapshot: TLeakCheck.TSnapshot;
Report: LeakString;
begin
Snapshot.Create;
LeakMemory;
Report := TLeakCheck.GetReport(Snapshot.Snapshot);
try
Writeln(string(Report));
finally
Report.Free;
end;
end;
begin
Application.Initialize;
DetectLeak;
Readln;
end.
Creating instance of TThread
(originally it was TThread.CreateAnonymousThread
but results are the same) causes 64 bytes of memory leak:
Total allocation count: 297 (12592 B)
Leak detected 02BB3DC0 size 64 B
00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 E8 03 00 00 00 00 00 00 00 00 00 00 00 00 00 00 | ????????????????????????????????
00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 | ????????????????????????????????
Stack trace when the memory block was allocated:
$00406E76 - LeakCheckMemLeak.exe - System.AllocMem + $A (4562 +25)
$004C4A53 - LeakCheckMemLeak.exe - System.Classes.TThread.WaitFor + $8F (15565 +23)
$005E4EB0 - LeakCheckMemLeak.exe - LeakCheckMemLeak.DetectLeak + $34 (24 +3)
$005ED5B9 - LeakCheckMemLeak.exe - LeakCheckMemLeak.LeakCheckMemLeak + $29 (35 +3)
$763E343D - kernel32.dll
$76F19832 - ntdll.dll
In other cases LeakCheck provided me name of class that instance leaked so I could add it to list of ignored, but in this case it does not. How can I suppress this "leak"?
One a side note, this and other leaks that I've encountered don't happen in GUI application. I guess, RTL preallocates memory for most of these objects before tests run.
FWIW the results I get after removing Forms and Application.Initialize is this:
Total allocation count: 113 (4152 B)
Leak detected 0262F540 size 44 B for class: TExternalThread
Leak detected 0260A988 size 20 B for class: TThreadList<System.Classes.TThread>
Leak detected 02618A90 size 8 B for class: TObject
Leak detected 026451F8 size 52 B for class: TList<System.Classes.TThread>
Leak detected 02618AC8 size 12 B
01 00 00 00 01 00 00 00 40 F5 62 02 | ????????@?b?
I know from using LeakCheck in Spring4D unit tests that this comes from the lazy initialization of some instances in TThread.GetCurrentThread
which gets called during your LeakMemory
routine - more precisely during TThread.Destroy
which calls WaitFor
(see System.Classes.pas
line 15764 in Delphi 10.2.3). This creates the instances that you see in the report I posted.
What we are doing in Spring4D and also in the tests at work is calling all kinds of methods and routines that we know cause some lazy initialization of instances (TEncoding
for example is another candidate) before running any test. This prevents lazy initializations during the test run which then manifest in the memory delta before and after the test. See InitializeLeakCheck
in Spring.TestRunner.pas
While you could configure LeakCheck to ignore these leaks it will affect performance significantly because it would find leaks to begin with. If these instances are initialized before changes are there is nothing to ignore later.