When The Debugger Leaks…
… you may end up chasing memory leaks that don’t exist.
I was at work investigating some bizarre behavior of our application when dealing with a big customer file and I had ReportMemoryLeaksOnShutdown
turned on as it was very likely there was some memory leaked.
So, I donned my LeakBuster suit, armed my LeakBlaster and started hunting the leaks, trying different workflows with different code-paths, putting some Breakpoints here or there with some Watches, and sure enough, I got a bunch of memory leaks reported upon closing the application. But those were somewhat bizarre, mainly UnicodeStrings with unhelpful stacktraces into the VCL like:
A memory block has been leaked. The size is: 36
This block was allocated ... and the stack trace (return addresses) at the time was:
4043E2 [System.pas][System][@GetMem][2979]
20036
The block is currently used for an object of class: Unknown
or
A memory block has been leaked. The size is: 20
This block was allocated ... and the stack trace (return addresses) at the time was:
404972 [System.pas][System][System.@GetMem][3693]
407B5B [System.pas][System][System.@NewUnicodeString][16751]
407D8C [System.pas][System][System.@UStrFromPWCharLen][17431]
...
407E63 [System.pas][System][System.InternalUStrFromPCharLen][17601]
The block is currently used for an object of class: UnicodeString
It took me some time to find a relatively simple workflow showing consistently a leak where I was pretty sure the code was OK and should not leak. Then I tried to run the application without debugging and it did not leak. And again within the debugger and it leaked again.
So, the debugger was leaking memory. I don’t remember ever seeing that before, except in the cases where calling some buggy code from the Evaluate dialog or in the Watches was causing a leak.
You can try yourself in D2010 or XE with this very simple application: Create New VCL Form Application, double click in the Form designer to create a FormCreate handler and replace the empty procedure by this code:
function Test(s: string): string;
begin
Result := 'test: ' + s;
end;
procedure TForm1.FormCreate(Sender: TObject);
begin
ReportMemoryLeaksOnShutdown := True;
ShowMessage(Test('toto'));
end;
As you can see, this code cannot possibly leak. Run it and, as expected, it does not leak.
Now put a break point on the ShowMessage line and create a watch to execute Test(‘boo’), checking the “Allow side effects and function calls” in the watch dialog. Run the application, it stops before the ShowMessage and you can see the ‘test: boo’ string value in the watch. Resume the execution, you get the ShowMessage and you can close the Application when the Main Form is shown.
Now, you get the dreaded Memory Leak Report dialog:
—————————
Unexpected Memory Leak
—————————
An unexpected memory leak has occurred.
The unexpected small block leaks are:85 – 92 bytes: UnicodeString x 1
—————————
The funny thing is that if you save this project “as is” and close Delphi, next time you restart Delphi and run it, it might not necessary leak even though you see the watch expression evaluated; you’d have to run it again or even open the watch dialog explictly and then boom! you’ll get the leak….
Anyway, as using “Evaluate” or “Watch” are common use cases when debugging, it’s very easy to find yourself with some strange memory leaks.
I have experienced this with D2010 and XE, with or without the full FastMM4. I don’t recall having this with D2007 or previous versions.
Do you Delphites out there see that behavior?
(not yet logged in QC, but it looks very similar to QC# 73762, so maybe that one just needs more visibility and more votes, and this new Use Case).