Detecting Memory Leaks

1. Introduction

"Memory leak" means that you allocated a memory for something, but didn’t deallocate it.

For example you created an instance of a class (by MyInstance := TObject.Create) but then did not free it (e.g. by calling FreAndNil(MyInstance)).

Note
In Pascal you generally need to take care to free the memory yourself. See freeing classes (modern Pascal introduction) for more information how to free the memory correctly.

We recommend that you check your applications for memory leaks and fix them, following the information on this page.

2. Why fix memory leaks?

Sometimes it is tempting to ignore some memory leaks. Your application works, so why should you care?

But we argue that it is a good idea to fix memory leaks, and fix them all, no exceptions. We also follow this rule strictly in the Castle Game Engine codebase (see our coding conventions).

Reasons:

  • The obvious reason to fix memory leaks is that they waste memory. This is especially important for large leaks (e.g. big number of textures or scenes) that may really cause a long-running application to exhaust the available memory.

    E.g. if a user will play your game for a while, loading more and more content. Once the application will use all available (RAM) memory, the system will start to use swap memory which is very slow. Once the swap memory is also finished, the application will just crash, with out of memory error.

  • While some small, or rare, memory leaks have a low chance of ever exhausting the available RAM, they make catching and fixing the large leaks harder. That’s because your "leak report" (produced by the tools we describe on this page) will get long and so you can easily miss larger leaks. The easiest solution is just to fix all leaks.

  • Finally, and this is actually likely the most important argument: memory leaks may indicate you don’t have a solid logic to control the allocation and deallocation. Maybe you just forgot that something should be deallocated, but maybe there’s a more serious bug in your code. Fixing memory leaks sometimes leads to fixing other bugs, with potentially more dire consequences.

3. FPC

Free Pascal Compiler has a unit HeapTrc to debug run-time memory allocation and deallocation.

3.1. Using HeapTrc in Castle Game Engine

Using HeapTrc with Castle Game Engine is the same as with any other FPC application:

  • Use compiler switches -gl -gh or (combined into one option) -glh.

  • -gh means that HeapTrc is used, -gl means that line information is visible (very useful to see where was the memory leak, i.e. which allocation was not followed by deallocation).

  • NOTE: do not include HeapTrc in the uses section explicitly. The -gh will automatically use the HeapTrc unit correctly.

There are various ways to pass these options to FPC:

  • If you use the build tool, you can call it like castle-engine --compiler-option=-glh compile to compile.

  • Alternatively, you can just specify detect_memory_leaks="true" in compiler options in CastleEngineManifest.xml.

  • Alternatively, you can use them for all your programs by adding to fpc.cfg file. You can add them only to the DEBUG builds (done by castle-engine --mode-debug compile) like this:

      #IFDEF DEBUG
      -gh
      -gl
      #ENDIF
  • If you compile using Lazarus: Note that HeapTrc is enabled by default in Lazarus Debug mode, which can be created and set in Project Options.

By default, HeapTrc will monitor all memory allocation and deallocation events during the program execution and will provide a thorough report after the execution stops in a regular way or due to an exception, unless the application process was killed by OS.

3.2. Interpreting the results

In effect, at the program’s exit, you will get a useful report about the allocated and not freed memory blocks (i.e. memory leaks). Each leak will have a stack trace to the allocation call. This allows to easily detect and fix memory leaks.

If everything is OK, the output looks like this:

Heap dump by heaptrc unit
12161 memory blocks allocated : 2290438/2327696
12161 memory blocks freed     : 2290438/2327696
0 unfreed memory blocks : 0
True heap size : 1212416
True free heap : 1212416

But when you have a memory leak, it tells you about it, and tells you where the relevant memory was allocated, like this:

Heap dump by heaptrc unit
4150 memory blocks allocated : 1114698/1119344
4099 memory blocks freed     : 1105240/1109808
51 unfreed memory blocks : 9458
True heap size : 851968
True free heap : 834400
Should be : 835904
Call trace for block $00007F9B14E42980 size 44
  $0000000000402A83 line 162 of xxx.lpr
  ...

3.3. Caveat: Ignore output when Halt occurred

When you exit with Halt, output will always show some memory leaks, that’s unavoidable right now. You should ignore the "Heap dump by heaptrc unit" output in this case.

Same thing applies when your program crashes with an unhandled exception.

3.4. Caveat: Windows GUI output is bothersome

The behavior in case of memory leaks on Windows GUI application is unfriendly. Memory leaks are displayed using a series of Windows modal message boxes, and you have to click through them, or kill the application.

It’s better to switch application to CONSOLE for debugging, and run it from command-line, to observe HeapTrc output.

Or use the advise below to redirect the output to file.

3.5. Advanced: Routing HeapTrc output to a file

By default, HeapTrc output is dumped into standard output (on Unix systems and on console Windows applications). However, for Windows GUI applications, the HeapTrc output is shown as a series of modal popup windows and can be very tedious to work with in case the output is extensive.

This behavior can be changed by explicitly requesting to dump HeapTrc output to a file by using SetHeapTraceOutput procedure. E.g. add SetHeapTraceOutput(URLToFilenameSafe(ApplicationConfig('heaptrc.log'))); in main project source file.

Note, that as this way the HeapTrc would not be shown explicitly after the program exits, the developer has to remember to analyze this file manually to check if there are any memory leaks.

4. Delphi

Delphi has ReportMemoryLeaksOnShutdown global variable. Set it to true to detect and report memory leaks.

To enable leak detection, just add this inside the main program file (.dpr):

ReportMemoryLeaksOnShutdown := true;

In effect, the memory leaks (if any) will be reported when the application ends. The leaks are reported as a GUI dialog when the application is a GUI ({$apptype GUI}, default with Delphi compiler). When the application is using a console ({$apptype CONSOLE}), the leaks are reported on the console. There’s nothing reported when there are no leaks.

If you’d like to show leaks only when running inside the debugger in Delphi IDE, you can make it conditional on DebugHook, like this:

ReportMemoryLeaksOnShutdown := DebugHook <> 0;
Note
It is only reports leaks on the Windows platform. But it compiles everywhere, there’s no need to use {$ifdef MSWINDOWS} around it.

To improve this documentation just edit this page and create a pull request to cge-www repository.