Sometimes after a regular FastMM memory leak test report you get a dialog like this:
The normal FastMM memory leak reporting dialog looks like this:
Searching for “Unexpected Memory Leak” in RTL or FastMM code did not reveal results, but that might be me not doing a proper search.
One big problem is that the regular memory leak dialog is being suppressed by setting SuppressMessageBoxes
to True
(see for instance my blog post Application shutdown: wait for all threads to terminate or not? or [WayBack] delphi – Generating a FASTMM report WITHOUT the shutdown dialog – Stack Overflow).
However the “Unexpected Memory Leak” message box is always shown.
Research
Location of the error message caption
GETMEM.INC
has an identifier LeakMessageTitle
:
LeakMessageTitle: _PAnsiChr = 'Unexpected Memory Leak';
- Unlike
FastMM4.pas
, GETMEM.INC
does not take into account SuppressMessageBoxes
.
- Like
FastMM4.pas
, GETMEM.INC
does take into account ReportMemoryLeaksOnShutdown
.
More on GETMEM.INC
: [WayBack] delphi – Reporting memory leaks on shutdown with a console application – Stack Overflow
Versioned FastMM4.pas
.
Complicating the hunt
Not all allocations go via the memory manager. A complicating factor is that:
- ALL
TMonitor.Create
allocations go through SysAllocMem
:
class function TMonitor.Create: PMonitor;
begin
if CacheLineSize = 0 then
AtomicExchange(CacheLineSize, GetCacheLineSize);
if (CPUCount > 1) and (FDefaultSpinCount = 0) then
AtomicExchange(FDefaultSpinCount, 1000);
if CacheLineSize > SizeOf(Result^) then
Result := SysAllocMem(CacheLineSize)
else
Result := SysAllocMem(SizeOf(Result^));
Result.FSpinCount := FDefaultSpinCount;
end;
- ALL
TMonitor.Destroy
deallocations go through SysFreeMem
:
procedure TMonitor.Destroy;
begin
if (MonitorSupport <> nil) and (FLockEvent <> nil) then
MonitorSupport.FreeSyncObject(FLockEvent);
SysFreeMem(@Self);
end;
Debugging this is easiest to set a breakpoint in the FastMM4.pas finalization section enabling a breakpoint group that has breakpoints on these methods inside GETMEM.INC
:
function SysGetMem(Size: NativeInt): Pointer;
function SysFreeMem(P: Pointer): Integer;
function SysReallocMem(P: Pointer; Size: NativeInt): Pointer;
function SysAllocMem(Size: NativeInt): Pointer;
For inspecting for instance an asm
construct like TSmallPoolBlockPoolHeader[edx]
, use a conversion PSmallBlockPoolHeader(Pointer(EDX))^,r
Poor mans shotgun approach
This will hide all the SysAllocMem
related leaks:
unit FastMM4WrapperUnit;
interface
{$ifdef UseFastMM4}
uses
FastMM4,
FastMM4Messages;
{$endif UseFastMM4}
implementation
initialization
//
finalization
// Disable GETMEM.INC reports that neglect SuppressMessageBoxes and NoErrMsg; this will effectively hide the leak as GETMEM.INC also does not write the leaks to a log file
{$ifdef UseFastMM4}
if SuppressMessageBoxes then
begin
{$WARN SYMBOL_PLATFORM OFF} NoErrMsg := True {$WARN SYMBOL_PLATFORM ON}; // no ShowMessage from the RTL (except for memory leaks)
ReportMemoryLeaksOnShutdown := False; // No ShowMessage from the RTL in the GETMEM.INC teardown
end;
{$endif UseFastMM4}
end.
IsConsole: needs linker option
Note that I tried embedding this in the then portion, but enabling IsConsole fails:
IsConsole := True; // can only force run-time error messages to be written to the console if the "" is set.
The reason is that this does not allocate a console handle, so you really need to ensure the linker has allocated a console for you by enabling
For more details, see my post console – When is System.IsConsole true in Delphi? – Stack Overflow.
–jeroen
Like this:
Like Loading...