Difference between revisions of "heaptrc"

From Free Pascal wiki
Jump to navigationJump to search
m (rearranged GlobalSkipIfNoLeaks info)
 
(94 intermediate revisions by 12 users not shown)
Line 1: Line 1:
'''heaptrc''' is a unit that can be used to debug allocation and deallocation of memory blocks. It keeps track of calls to getmem/freemem, and, implicitly, of New/Dispose statements.
+
{{heaptrc}}
  
When a program using heaptrc ends, heaptrc can write out the total memory used and a list of allocated but not freed blocks to a file.
+
'''<syntaxhighlight lang="pascal" inline>Heaptrc</syntaxhighlight>''' is a unit that can be used to debug allocation and deallocation of memory blocks.
When run in the console (*nix or Windows), heaptrc will print this output to screen unless otherwise instructed.
+
It keeps track of calls to {{Doc|package=RTL|unit=system|identifier=getmem|text=<syntaxhighlight lang="pascal" inline>GetMem</syntaxhighlight>}}/{{Doc|package=RTL|unit=system|identifier=freemem|text=<syntaxhighlight lang="pascal" inline>FreeMem</syntaxhighlight>}} calls, and, implicitly, of {{Doc|package=RTL|unit=system|identifier=new|text=<syntaxhighlight lang="pascal" inline>New</syntaxhighlight>}}/{{Doc|package=RTL|unit=system|identifier=dispose|text=<syntaxhighlight lang="pascal" inline>Dispose</syntaxhighlight>}} statements.
In Lazarus GUI programs on Windows, the output will appear in numerous small dialog boxes, which may be very unpractical.
 
  
 +
{{Warning|1=
 +
Do not add the <syntaxhighlight lang="pascal" inline>Heaptrc</syntaxhighlight> unit manually.
 +
The <syntaxhighlight lang="pascal" inline>Heaptrc</syntaxhighlight> unit needs to be loaded before <syntaxhighlight lang="pascal" inline>Lineinfo</syntaxhighlight> and only the compiler can do that.
  
[[File:Win heaptrc output no error.png|Standard output of heaptrc on Windows (despite of the title there is no error in the application)]]
+
<syntaxhighlight lang="pascal" inline>Heaptrc</syntaxhighlight> is also a memory manager, so do not try to use any memory manager&nbsp;– including <syntaxhighlight lang="pascal" inline>Heaptrc</syntaxhighlight> itself&nbsp;– in the [[Uses|<syntaxhighlight lang="pascal" inline>uses</syntaxhighlight> clause]], because that may lead to memory corruption and false results.
  
 +
This topic contains a note with example code to handle such a case in a generic way.
 +
}}
  
On *nix (including BSD, Linux and Mac OS X), by default, nothing will be shown for GUI programs. See [[leakview]] for details on how to make use of heaptrc effectively.
+
When a program using Heaptrc ends, Heaptrc can write out the total memory used and a list of allocated but not freed blocks to a file.
 +
When run in the console (*nix or Windows), Heaptrc will print this output to screen unless otherwise instructed.
 +
In Lazarus GUI programs on Windows, the output will appear in numerous small dialog boxes, which may be very unpractical, although you can redirect output to file.
 +
 
 +
[[File:Win heaptrc output no error.png|Standard output of Heaptrc on Windows (despite of the title there is no error in the application)]]
 +
 
 +
On *nix (including BSD, Linux and macOS), by default, nothing will be shown for GUI programs. In this case, to see heaptrc output when you terminate your program (GUI or non-GUI), open "Console In/Output" (Ctrl+Alt+O or View -> Debug Window -> ...) 
 +
 
 +
See [[leakview]] for details on how to make use of Heaptrc effectively.
  
 
== Usage ==
 
== Usage ==
Heaptrc can be added to a project in two ways in FPC.
+
=== Using Heaptrc in FPC ===
 +
Add a parameter <syntaxhighlight lang="text" inline>-gh</syntaxhighlight> to your compilation command line or to <syntaxhighlight lang="text" inline>fpc.cfg</syntaxhighlight>.
 +
 
 +
<syntaxhighlight lang="bash">fpc -gh Helloworld.pas</syntaxhighlight>
 +
or usually combined with line info:
 +
<syntaxhighlight lang="bash">fpc -glh Helloworld.pas</syntaxhighlight>
  
1) Explicitly add the unit to your uses section. But read [[heaptrc#Warning|warning]] below.
+
This will add Heaptrc implicitly as a hidden first unit of the program's uses clause.
<syntaxhighlight>
 
program Helloworld;
 
  
uses
+
{{Warning|All examples given on this page can only be used in the '''main project file'''. That is, in a file that begins with <syntaxhighlight inline lang="pascal">Program ...</syntaxhighlight>, and not <syntaxhighlight inline lang="pascal">Unit ...</syntaxhighlight>.
  heaptrc, cthreads, Classes, SysUtils
+
}}
 +
 
 +
{{Warning|Don't confuse using <syntaxhighlight inline lang="pascal">{$if declared(UseHeapTrace)}}</syntaxhighlight> with using <syntaxhighlight inline lang="pascal">{$if defined(UseHeapTrace)}}</syntaxhighlight> or <syntaxhighlight inline lang="pascal">{$ifdef UseHeapTrace}}</syntaxhighlight>. To check heaptrc you need the first option since the others will always be false.
 +
}}
  
 +
You can test in code if Heaptrc is active by examining the global constant {{Doc|package=RTL|unit=heaptrc|identifier=useheaptrace|text='''<syntaxhighlight lang="pascal" inline>UseHeapTrace</syntaxhighlight>'''}} for the presence of Heaptrc and its status like so:
 +
<syntaxhighlight lang="pascal">
 +
program PossiblyHeaptraced(Input, Output, StdErr);
 
begin
 
begin
  writeln('hello world');
+
{$if declared(UseHeapTrace)}
 +
WriteLn('Heaptrc is used.');
 +
// Heaptrc reports can be turned off when linked in... so true or false
 +
WriteLn('Heaptrc is active: ', UseHeapTrace);
 +
// you can subsequently test/set any Heaptrc reporting options
 +
{$else}
 +
WriteLn('No trace of Heaptrc.');
 +
{$endIf}
 
end.
 
end.
 
</syntaxhighlight>
 
</syntaxhighlight>
  
2) Add a parameter -gh to your compilation command line
+
=== Using Heaptrc in Lazarus ===
 +
To enable this in your Lazarus project:
 +
# Go to ''Project Options/Linking'' and
 +
# in the Debugging section enable ''Use Heaptrc unit (check for mem-leaks) (-gh)''
 +
 
 +
You can test for the presence of <syntaxhighlight lang="pascal" inline>Heaptrc</syntaxhighlight> in a similar manner as in the above example by testing for the presence of <syntaxhighlight lang="pascal" inline>UseHeapTrace</syntaxhighlight> in your Project.lpr file.
 +
<syntaxhighlight lang="pascal">
 +
{$if declared(UseHeapTrace)}
 +
// ... do something
 +
 
 +
// test if active
 +
if UseHeapTrace then
 +
begin
 +
// ...
 +
end;
 +
{$endIf}
 +
</syntaxhighlight>
 +
 
 +
=== Show report only on leak ===
 +
If you want to show <syntaxhighlight lang="pascal" inline>Heaptrc</syntaxhighlight> report dialog only if there were leaks in your application, then put this [[Becomes|assignment]] somewhere in your main project source file:
 +
<syntaxhighlight lang="pascal">
 +
{$if declared(UseHeapTrace)}
 +
GlobalSkipIfNoLeaks := True; // supported as of debugger version 3.2.0
 +
{$endIf}
 +
</syntaxhighlight>
 +
 
 +
=== Programmatically disable report ===
 +
If the <syntaxhighlight lang="pascal" inline>UseHeapTrace</syntaxhighlight> variable is <syntaxhighlight lang="pascal" inline>false</syntaxhighlight> when the program exits, then the leak will not be reported, even if it is detected. You can use this in your code:
 +
 
 +
<syntaxhighlight lang="pascal">
 +
UseHeapTrace := false;
 +
</syntaxhighlight>
  
fpc -gh helloworld.pas
+
Note that changing <syntaxhighlight lang="pascal" inline>UseHeapTrace</syntaxhighlight> can neither turn heaptrc on nor off, since the memory manager cannot be changed while the program is running. This only controls the <ins>output of the leak message</ins> at the end of the program.
  
This will add heaptrc implicitly as the first unit of uses clauss.
+
This is worth considering, for example, when using [https://www.freepascal.org/docs-html/rtl/heaptrc/keepreleased.html <syntaxhighlight inline>KeepReleased</syntaxhighlight>] - this requires a lot of additional memory, and setting <syntaxhighlight lang="pascal" inline>UseHeapTrace := false</syntaxhighlight> will not free it.
  
=== Lazarus ===
+
=== Continue execution even on heap error ===
To enable this in your Lazarus project: go to Project Options/Linking and in the Debugging section enable ''Use Heaptrc unit (check for mem-leaks) (-gh)''
+
If you want your application to continue execution even in case of a heap error then manipulate {{Doc|package=RTL|unit=heaptrc|identifier=haltonerror|text=<syntaxhighlight lang="pascal" inline>HaltOnError</syntaxhighlight> constant}} at program startup:
 +
<syntaxhighlight lang="pascal">
 +
HaltOnError := False;
 +
</syntaxhighlight>
  
=== Show report only on leak ===
+
=== Redirect report to file ===
If you want to show heaptrc report dialog only if there were leaks in your application, then put this command somewhere in your main project source file:
+
If you want to redirect leak report to file then add this to beginning of you main project file:
<syntaxhighlight>
+
<syntaxhighlight lang="pascal">
  GlobalSkipIfNoLeaks := true;
+
SetHeapTraceOutput('Trace.log'); // supported as of debugger version 3.2.0
 
</syntaxhighlight>
 
</syntaxhighlight>
  
== Warning ==
+
=== Why Heaptrc should not be added to the uses clause manually ===
Don't put heaptrc into uses section more than one time. It's preferred if you never put into a unit uses section, but only into program uses section.
+
You should never add Heaptrc manually in a normal program, because the Heaptrc unit needs to be loaded before Lineinfo for debugging to work properly.
  
 +
Decoding dwarf debugging info efficiently requires a working heap manager and this means that Heaptrc needs to be loaded before the the [[DWARF]] line info decoding unit which is loaded by -gl, so Heaptrc cannot be used explicitly.
  
[http://forum.lazarus.freepascal.org/index.php/topic,31459.0.html by avra on Lazarus forum]
+
Only the compiler itself can insert the unit in its proper place as a hidden first unit in the uses clause.
I would like to share my example of wrong heaptrc usage...
+
Adding the unit by hand can cause all kind of unwanted side effects.
+
E.g. crashes, reported Lineinfo is not reliable and not all leaks can reliably be reported.
After some hard debugging and troubleshooting I wanted to dig a little into heaptrc unit to see if there was anything
 
more inside of it which I  could have used along with TLogger. Therefore besides being the first unit in project,
 
I have included it in one of my other units where I temporarily needed it.
 
 
What a wrong move!!!  >:(  :'( %)
 
 
In meantime I have solved my problem but completely forgotten to remove heaptrc from the uses in that other unit.  
 
Well, many, many man hours later  I have figured out why my application had sudden leaks, hangs and freezes,
 
and totally different errors with heaptrc used or not with a project.  What a relief!
 
 
I wish IDE had at least warned me that I had heaptrc which was not the first used unit in a project, or that I had 2 such units.
 
 
Doc says only that it should be the first used unit in a project, but nothing said that it was dangerous to include it once more.
 
 
Cheers!
 
  
== See also ==
+
This has always been the case, but is only properly documented from FPC version 3.0.2.
* [[leakview]]: Examples how to enable heaptrc in Lazarus and Free Pascal.
+
So if you still see Heaptrc in your uses clause, remove it! for debugging and reporting to work properly.
* [[doc:rtl/heaptrc/|RTL Reference for unit 'heaptrc']]
+
{{Note|If your program is designed to use an alternative memory manager, you can adapt your program's uses clause like so:
 +
<syntaxhighlight lang="pascal">program AlternativeMemoryManager(Input, Output, StdErr);
 +
{$mode ObjFPC}
 +
uses
 +
// This will conditionally switch in a memory manager
 +
// based on the presence of Heaptrc
 +
{$if not declared(UseHeapTrace)}
 +
CMem,
 +
{$endIf}
 +
SysUtils, Classes; // the latter two are just to test.
  
 +
begin
 +
{$if declared(UseHeapTrace)}
 +
WriteLn('Heaptrc is used.', ' Heaptrc is active: ', UseHeapTrace);
 +
{$else}
 +
WriteLn('No trace of Heaptrc.');
 +
{$endIf}
 +
end.
 +
</syntaxhighlight>
 +
In the above example the conditional in the uses clause makes sure that the CMem memory manager is only compiled in if the Heaptrc option is not used.
 +
}}
  
[[Category:Debugging]]
+
== See also ==
 +
* {{gitlab|issue|Documentation|30637}}
 +
* [[leakview]]: Examples how to enable Heaptrc in Lazarus and Free Pascal.
 +
* [[doc:rtl/heaptrc/|RTL Reference for unit 'Heaptrc']] (this link is not yet up-to-date)

Latest revision as of 00:18, 13 April 2024

English (en) русский (ru)

Heaptrc is a unit that can be used to debug allocation and deallocation of memory blocks. It keeps track of calls to GetMem/FreeMem calls, and, implicitly, of New/Dispose statements.

Warning-icon.png

Warning: Do not add the Heaptrc unit manually. The Heaptrc unit needs to be loaded before Lineinfo and only the compiler can do that. Heaptrc is also a memory manager, so do not try to use any memory manager – including Heaptrc itself – in the uses clause, because that may lead to memory corruption and false results. This topic contains a note with example code to handle such a case in a generic way.

When a program using Heaptrc ends, Heaptrc can write out the total memory used and a list of allocated but not freed blocks to a file. When run in the console (*nix or Windows), Heaptrc will print this output to screen unless otherwise instructed. In Lazarus GUI programs on Windows, the output will appear in numerous small dialog boxes, which may be very unpractical, although you can redirect output to file.

Standard output of Heaptrc on Windows (despite of the title there is no error in the application)

On *nix (including BSD, Linux and macOS), by default, nothing will be shown for GUI programs. In this case, to see heaptrc output when you terminate your program (GUI or non-GUI), open "Console In/Output" (Ctrl+Alt+O or View -> Debug Window -> ...)

See leakview for details on how to make use of Heaptrc effectively.

Usage

Using Heaptrc in FPC

Add a parameter -gh to your compilation command line or to fpc.cfg.

fpc -gh Helloworld.pas

or usually combined with line info:

fpc -glh Helloworld.pas

This will add Heaptrc implicitly as a hidden first unit of the program's uses clause.

Warning-icon.png

Warning: All examples given on this page can only be used in the main project file. That is, in a file that begins with Program ..., and not Unit ....

Warning-icon.png

Warning: Don't confuse using {$if declared(UseHeapTrace)}} with using {$if defined(UseHeapTrace)}} or {$ifdef UseHeapTrace}}. To check heaptrc you need the first option since the others will always be false.

You can test in code if Heaptrc is active by examining the global constant UseHeapTrace for the presence of Heaptrc and its status like so:

program PossiblyHeaptraced(Input, Output, StdErr);
begin
	{$if declared(UseHeapTrace)}
	WriteLn('Heaptrc is used.');
	// Heaptrc reports can be turned off when linked in... so true or false
	WriteLn('Heaptrc is active: ', UseHeapTrace); 
	// you can subsequently test/set any Heaptrc reporting options
	{$else}
	WriteLn('No trace of Heaptrc.');
	{$endIf}
end.

Using Heaptrc in Lazarus

To enable this in your Lazarus project:

  1. Go to Project Options/Linking and
  2. in the Debugging section enable Use Heaptrc unit (check for mem-leaks) (-gh)

You can test for the presence of Heaptrc in a similar manner as in the above example by testing for the presence of UseHeapTrace in your Project.lpr file.

{$if declared(UseHeapTrace)}
// ... do something

// test if active
if UseHeapTrace then
begin
	// ...
end;
{$endIf}

Show report only on leak

If you want to show Heaptrc report dialog only if there were leaks in your application, then put this assignment somewhere in your main project source file:

{$if declared(UseHeapTrace)}
GlobalSkipIfNoLeaks := True; // supported as of debugger version 3.2.0
{$endIf}

Programmatically disable report

If the UseHeapTrace variable is false when the program exits, then the leak will not be reported, even if it is detected. You can use this in your code:

UseHeapTrace := false;

Note that changing UseHeapTrace can neither turn heaptrc on nor off, since the memory manager cannot be changed while the program is running. This only controls the output of the leak message at the end of the program.

This is worth considering, for example, when using KeepReleased - this requires a lot of additional memory, and setting UseHeapTrace := false will not free it.

Continue execution even on heap error

If you want your application to continue execution even in case of a heap error then manipulate HaltOnError constant at program startup:

HaltOnError := False;

Redirect report to file

If you want to redirect leak report to file then add this to beginning of you main project file:

SetHeapTraceOutput('Trace.log'); // supported as of debugger version 3.2.0

Why Heaptrc should not be added to the uses clause manually

You should never add Heaptrc manually in a normal program, because the Heaptrc unit needs to be loaded before Lineinfo for debugging to work properly.

Decoding dwarf debugging info efficiently requires a working heap manager and this means that Heaptrc needs to be loaded before the the DWARF line info decoding unit which is loaded by -gl, so Heaptrc cannot be used explicitly.

Only the compiler itself can insert the unit in its proper place as a hidden first unit in the uses clause. Adding the unit by hand can cause all kind of unwanted side effects. E.g. crashes, reported Lineinfo is not reliable and not all leaks can reliably be reported.

This has always been the case, but is only properly documented from FPC version 3.0.2. So if you still see Heaptrc in your uses clause, remove it! for debugging and reporting to work properly.

Light bulb  Note: If your program is designed to use an alternative memory manager, you can adapt your program's uses clause like so:

program AlternativeMemoryManager(Input, Output, StdErr);
{$mode ObjFPC}
uses
	// This will conditionally switch in a memory manager
	// based on the presence of Heaptrc
	{$if not declared(UseHeapTrace)}
	CMem,
	{$endIf}
	SysUtils, Classes; // the latter two are just to test.

begin
	{$if declared(UseHeapTrace)}
	WriteLn('Heaptrc is used.', ' Heaptrc is active: ', UseHeapTrace);
	{$else}
	WriteLn('No trace of Heaptrc.');
	{$endIf}
end.

In the above example the conditional in the uses clause makes sure that the CMem memory manager is only compiled in if the Heaptrc option is not used.

See also