Subsections

- 1 Purpose
- 2 Usage
- 3 Constants, Types and variables
- 4 Functions and procedures
  - 1 DumpHeap
  - 2 MarkHeap
  - 3 SetExtraInfo
  - 4 SetHeapTraceOutput

# 9 The HEAPTRC unit.

This chapter describes the HEAPTRC unit for Free Pascal. It was written by Pierre Muller. It is system independent, and works on all supported systems.

# 1 Purpose

The HEAPTRC unit can be used to debug your memory allocation/deallocation. It keeps track of the calls to getmem/freemem, and, implicitly, of New/Dispose statements.

When the program exits, or when you request it explicitly. It displays the total memory used, and then dumps a list of blocks that were allocated but not freed. It also displays where the memory was allocated.

If there are any inconsistencies, such as memory blocks being allocated or freed twice, or a memory block that is released but with wrong size, this will be displayed also.

The information that is stored/displayed can be customized using some constants.

# 2 Usage

All that you need to do is to include heaptrc in the uses clause of your program. Make sure that it is the first unit in the clause, otherwise memory allocated in initialization code of units that precede the heaptrc unit will not be accounted for, causing an incorrect memory usage report.

If you use the `-gh` switch, the compiler will insert the unit by itself, so you don't have to include it in your uses clause.

The following example shows how to use the heaptrc unit.

Example

      Program heapex;

      { Program used to demonstrate the usage of heaptrc unit }

      Uses heaptrc;

      Var P1 : ^Longint;
          P2 : Pointer;
          I : longint;

      begin
        New(P1);
        // causes previous allocation not to be de-allocated
        New(P1);
        Dispose(P1);
        For I:=1 to 10 do
          begin
          GetMem (P2,128);
          // When I is even, deallocate block. We loose 5 times 128
          // bytes this way.
          If (I mod 2) = 0 Then FreeMem(P2,128);
          end;
        GetMem(P2,128);
        // This will provoke an error and a memory dump
        Freemem (P2,64);
      end.

This is the memory dump shown when running this program:

    Marked memory at 0040FA50 invalid
    Wrong size : 128 allocated 64 freed
      0x00408708
      0x0040CB49
      0x0040C481
    Call trace for block 0x0040FA50 size 128
      0x0040CB3D
      0x0040C481

If you use the lineinfo unit (or use the `-gl` switch) as well, then heaptrc will also give you the filenames and line-numbers of the procedures in the backtrace:

    Marked memory at 00410DA0 invalid
    Wrong size : 128 allocated 64 freed
      0x004094B8
      0x0040D8F9  main,  line 25 of heapex.pp
      0x0040D231
    Call trace for block 0x00410DA0 size 128
      0x0040D8ED  main,  line 23 of heapex.pp
      0x0040D231

If lines without filename/line-number occur, this means there is a unit which has no debug info included.

# 3 Constants, Types and variables

The `FillExtraInfoType` is a procedural type used in the SetExtraInfo call.

    type
        FillExtraInfoType = procedure(p : pointer);

The following typed constants allow to fine-tune the standard dump of the memory usage by DumpHeap:

    const
      tracesize = 8;
      quicktrace : boolean = true;
      HaltOnError : boolean = true;
      keepreleased : boolean = false;
      add_tail : boolean = true;
      usecrc : boolean = true

`Tracesize` specifies how many levels of calls are displayed of the call stack during the memory dump. If you specify `keepreleased:=True` then half the `TraceSize` is reserved for the `GetMem` call stack, and the other half is reserved for the `FreeMem` call stack. For example, the default value of 8 will cause eight levels of call frames to be dumped for the getmem call if `keepreleased` is `False`. If `KeepReleased` is true, then 4 levels of call frames will be dumped for the `GetMem` call and 4 frames wil be dumped for the `FreeMem` call. If you want to change this value, you must recode the heaptrc unit.

`Quicktrace` determines whether the memory manager checks whether a block that is about to be released is allocated correctly. This is a rather time consuming search, and slows program execution significantly, so by default it is set to `False`.

If `HaltOnError` is set to `True` then an illegal call to `FreeMem` will cause the memory manager to execute a `halt(1)` instruction, causing a memory dump. By Default it is set to `True`.

If `keepreleased` is set to true, then a list of freed memory blocks is kept. This is useful if you suspect that the same memory block is released twice. However, this option is very memory intensive, so use it sparingly, and only when it's really necessary.

If `add_tail` is `True` (the default) then a check is also performed on the memory location just behind the allocated memory.

If `usecrc` is `True` (the default) then a crc check is performed on locations before and after the allocated memory. This is useful to detect memory overwrites.

# 4 Functions and procedures

##
1 DumpHeap

Declaration
  `procedure DumpHeap;`
Description
  DumpHeap dumps to standard output a summary of memory usage. It is called automatically by the heaptrc unit when your program exits (by instaling an exit procedure), but it can be called at any time
Errors
  None.
See also
  MarkHeap

##
2 MarkHeap

Declaration
  `procedure MarkHeap;`
Description
  MarkHeap marks all memory blocks with a special signature. You can use this if you think that you corruped the memory.
Errors
  None.
See also
  DumpHeap

##
3 SetExtraInfo

Declaration
  `procedure SetExtraInfo( size : longint;func : FillExtraInfoType);`
Description
  You can use `SetExtraInfo` to store extra info in the blocks that the heaptrc unit reserves when tracing getmem calls. `Size` indicates the size (in bytes) that the trace mechanism should reserve for your extra information. For each call to `getmem`, `func` will be called, and passed a pointer to the memory reserved.

  When dumping the memory summary, the extra info is shown as Longint values.

Errors
  You can only call `SetExtraInfo` if no memroy has been allocated yet. If memory was already allocated prior to the call to `SetExtraInfo`, then an error will be displayed on standard error output, and a DumpHeap is executed.
See also
  DumpHeap,SetHeapTraceOutput

Example

      Program heapex;

      { Program used to demonstrate the usage of heaptrc unit }

      Uses heaptrc;

      Var P1 : ^Longint;
          P2 : Pointer;
          I : longint;
          Marker : Longint;

      Procedure SetMarker (P : pointer);

      Type PLongint = ^Longint;

      begin
        PLongint(P)^:=Marker;
      end;

      Procedure  Part1;

      begin
        // Blocks allocated here are marked with $FFAAFFAA = -5570646
        Marker := $FFAAFFAA;
        New(P1);
        New(P1);
        Dispose(P1);
        For I:=1 to 10 do
          begin
          GetMem (P2,128);
          If (I mod 2) = 0 Then FreeMem(P2,128);
          end;
        GetMem(P2,128);
      end;

      Procedure  Part2;

      begin
        // Blocks allocated here are marked with $FAFAFAFA = -84215046
        Marker := $FAFAFAFA;
        New(P1);
        New(P1);
        Dispose(P1);
        For I:=1 to 10 do
          begin
          GetMem (P2,128);
          If (I mod 2) = 0 Then FreeMem(P2,128);
          end;
        GetMem(P2,128);
      end;

      begin
       SetExtraInfo(SizeOf(Marker),@SetMarker);
       Writeln ('Part 1');
       part1;
       Writeln('Part 2');
       part2;
      end.

##
4 SetHeapTraceOutput

Declaration
  `Procedure SetHeapTraceOutput(const name : string);`
Description
  SetHeapTraceOutput sets the filename into which heap trace info will be written. By default information is written to standard output, this function allows you to redirect the information to a file with full filename `name`.
Errors
  If the file cannot be written to, errors will occur when writing the trace.
See also
  SetExtraInfo