Difference between revisions of "heaptrc"
(39 intermediate revisions by 9 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}}☺ |
+ | |||
+ | '''<syntaxhighlight lang="pascal" inline>heaptrc</syntaxhighlight>''' is a unit that can be used to debug allocation and deallocation of memory blocks. | ||
+ | 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. | ||
+ | |||
+ | {{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. | ||
+ | |||
+ | <syntaxhighlight lang="pascal" inline>Heaptrc</syntaxhighlight> is also a memory manager, so do not try to use any memory manager – including <syntaxhighlight lang="pascal" inline>heaptrc</syntaxhighlight> itself – 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. | ||
+ | }} | ||
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 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. | 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. | + | 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)]] | [[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 | + | On *nix (including BSD, Linux and macOS), by default, nothing will be shown for GUI programs. |
+ | See [[leakview]] for details on how to make use of heaptrc effectively. | ||
== Usage == | == Usage == | ||
− | + | === Using heaptrc in FPC === | |
− | Add a parameter -gh to your compilation command line or to fpc.cfg | + | 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> | ||
This will add heaptrc implicitly as a hidden first unit of the program's uses clause. | This will add heaptrc implicitly as a hidden first unit of the program's uses clause. | ||
− | You can test in code if heaptrc is active by examining the global | + | 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> | + | <syntaxhighlight lang="pascal"> |
− | program | + | program PossiblyHeaptraced(Input, Output, StdErr); |
begin | begin | ||
− | {$if declared(UseHeapTrace)} | + | {$if declared(UseHeapTrace)} |
− | + | WriteLn('Heaptrc is used.'); | |
− | + | // heaptrc reports can be turned off when linked in... so true or false | |
− | {$else} | + | 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> | ||
+ | |||
+ | Please note, that <syntaxhighlight lang="text" inline>{$if declared(UseHeapTrace)}</syntaxhighlight> does only work in a program, not in a unit. | ||
+ | |||
+ | Heaptrc does not work if you use it with FPC 3.0.4 on Linux and your program calls function <syntaxhighlight lang="text" inline>System.Get_CmdLine</syntaxhighlight>, in which case you will get at program end many EAccessViolation error messages. This seems to be a bug, e.g. in FPC 3.2.0-beta rev 43824 this problem does not occur. | ||
=== Using heaptrc in Lazarus === | === Using heaptrc in Lazarus === | ||
− | To enable this in your Lazarus project: | + | 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 heaptrc in a similar manner as in the above example by testing for the presence of UseHeapTrace in your project.lpr file. | + | 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> | + | <syntaxhighlight lang="pascal"> |
{$if declared(UseHeapTrace)} | {$if declared(UseHeapTrace)} | ||
− | //... do something | + | // ... do something |
− | // test if active | + | |
− | if UseHeapTrace then ... | + | // test if active |
− | {$ | + | if UseHeapTrace then |
+ | begin | ||
+ | // ... | ||
+ | end; | ||
+ | {$endIf} | ||
</syntaxhighlight> | </syntaxhighlight> | ||
=== Show report only on leak === | === Show report only on leak === | ||
− | If you want to show heaptrc report dialog only if there were leaks in your application, then put this | + | 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> | + | <syntaxhighlight lang="pascal"> |
− | + | {$if declared(UseHeapTrace)} | |
− | + | GlobalSkipIfNoLeaks := True; // supported as of debugger version 3.2.0 | |
− | + | {$endIf} | |
</syntaxhighlight> | </syntaxhighlight> | ||
=== Programmatically disable report === | === Programmatically disable report === | ||
− | If you want to disable report from your code then you can directly manipulate UseHeapTrace | + | If you want to disable report from your code then you can directly manipulate <syntaxhighlight lang="pascal" inline>UseHeapTrace</syntaxhighlight> constant at program startup: |
− | <syntaxhighlight> | + | <syntaxhighlight lang="pascal"> |
− | + | UseHeapTrace := False; | |
</syntaxhighlight> | </syntaxhighlight> | ||
+ | This will in effect change the behavior to a normal memory manager. | ||
=== Continue execution even on heap error === | === Continue execution even on heap error === | ||
− | If you want | + | 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> | + | <syntaxhighlight lang="pascal"> |
− | + | HaltOnError := False; | |
</syntaxhighlight> | </syntaxhighlight> | ||
=== Redirect report to file === | === Redirect report to file === | ||
If you want to redirect leak report to file then add this to beginning of you main project file: | If you want to redirect leak report to file then add this to beginning of you main project file: | ||
− | <syntaxhighlight> | + | <syntaxhighlight lang="pascal"> |
− | + | SetHeapTraceOutput('trace.log'); // supported as of debugger version 3.2.0 | |
</syntaxhighlight> | </syntaxhighlight> | ||
Line 71: | Line 99: | ||
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. | 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. | + | 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. | 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. | + | 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. | 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. | So if you still see heaptrc in your uses clause, remove it! for debugging and reporting to work properly. | ||
+ | {{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. | ||
+ | }} | ||
== See also == | == See also == | ||
− | * | + | * https://bugs.freepascal.org/view.php?id=30637 |
* [[leakview]]: Examples how to enable heaptrc in Lazarus and Free Pascal. | * [[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) | * [[doc:rtl/heaptrc/|RTL Reference for unit 'heaptrc']] (this link is not yet up-to-date) | ||
− | |||
− |
Revision as of 20:19, 10 January 2022
│
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: 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.
On *nix (including BSD, Linux and macOS), by default, nothing will be shown for GUI programs. 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.
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.
Please note, that {$if declared(UseHeapTrace)}
does only work in a program, not in a unit.
Heaptrc does not work if you use it with FPC 3.0.4 on Linux and your program calls function System.Get_CmdLine
, in which case you will get at program end many EAccessViolation error messages. This seems to be a bug, e.g. in FPC 3.2.0-beta rev 43824 this problem does not occur.
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 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 you want to disable report from your code then you can directly manipulate UseHeapTrace
constant at program startup:
UseHeapTrace := False;
This will in effect change the behavior to a normal memory manager.
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.
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
- https://bugs.freepascal.org/view.php?id=30637
- leakview: Examples how to enable heaptrc in Lazarus and Free Pascal.
- RTL Reference for unit 'heaptrc' (this link is not yet up-to-date)