Fixing Memory Leaks With AQtime

Download File:
KnTour.zip

Applies to: AQtime 7.10

Introduction

It is a good programming practice to check how your application handles memory and whether it has any memory leaks. AQtime, SmartBear's integrated profiling toolkit, includes the Allocation profiler that allows you to trace memory leaks in your application and check whether any allocated memory blocks or objects remain in memory after your application execution is over. It also collects information on where in the source code those leaked objects are created, which allows you to fix them easily.

This article describes how to find and fix memory leaks in a sample application using AQtime's Allocation profiler. We are going to profile the application with the Allocation profiler, analyze the results and apply what we learn to fix memory leaks in the application's source code. Then we will profile the application once again to see the improvements.

About Sample Application

In this article we will demonstrate how to use AQtime to find and fix memory leaks in a sample Delphi application named KnTour. You can download this application with source code from the Downloads section at the top right of the article.

Figure 1. Knight Tour Application Main Form

Figure 1. Knight Tour Application Main Form

The application finds solutions for the Knight's Tour problem. A brief overview of this problem is as follows.

Consider an NxN square board. The chess knight starts out on a square and the goal is to get to land on all other squares covering each square only once.

A knight always jumps in an L-shaped pattern, two squares in one direction and one square off to one side of this. A square is covered only if a move ends on it, not if the knight jumps over it.

Figure 2. A Graphical Representation of the Knight Piece Movements

Figure 2. A Graphical Representation of the Knight Piece Movements

The KnTour application uses backtracking algorithm to find all legal solutions that meet the conditions without repeating. To start searching for solutions, click Start in the application main window. The application then displays the analyzed paths and the total number of found solutions in real time. Once the analysis is stopped, you can select a specific solution from the - list and click Play to replay it step by step.

By default, the application uses a 5x5 board and the knight starts from the top left corner, but you can customize the board size and the knight's initial position to find other possible knight tours.

Note: The KnTour application with the source code can be downloaded from the Downloads section at the top right of the article. To build the application from sources, you need Borland Delphi 7 or later.

Preparing Application for Profiling

Before we can start application profiling, we need to enable the application for profiling. This is done by rebuilding the application with debug information. Debug information allows AQtime to relate the application's binary code to the source code, track class names of allocated and leaked objects, show object allocation stack details and so on.

The following images demonstrate the required compiler options. For detailed instructions, please refer to the Compiler Settings for Borland Delphi 3-7 topic in AQtime documentation.

Figure 3. Compiler Settings for Delphi 7

Figure 3. Compiler Settings for Delphi 7

Preparing AQtime Project

Once the application is ready for profiling, we create a new profiling project in AQtime. Then we add the application executable to the list of profiled modules. To find memory leaks, we will use AQtime's Allocation profiler with the Full Check by Classes setting.

Figure 4. Preparing an AQtime Project for Profiling

Figure 4. Preparing an AQtime Project for Profiling

Also, to be able to view the application source code in AQtime's Code Editor, we need to specify the source code search paths. To do this, select the Project | Search Directories menu command and specify the folder to which you have downloaded and unpacked the application code.

Figure 5. Specifying the Path to the Profiled Application Source Code

Figure 5. Specifying the Path to the Profiled Application Source Code

Running Memory Profiling

To start profiling, click Run on the Standard toolbar.

Figure 6. Starting Profiling

Figure 6. Starting Profiling

The Run Settings dialog opens where you can specify memory profiling options.

Figure 7. Specifying the Allocation Profiler Settings

Figure 7. Specifying the Allocation Profiler Settings

In the Collect stack information drop-down box we select the "By lines" item for the profiler to include information on source code lines in the collected call stack information. This will allow determining at which source line a leaked object is created. We leave the other options disabled for simplicity and then click Run.

Let us simulate user actions with the application:

  1. Click Start to initiate a search for solutions.
  2. Wait until at least several solutions are found and click Stop to terminate the search.
  3. Select a solution from the drop-down list and click Play to play the solution step by step.
  4. Close the application.

Figure 8. Performing User Actions over the Profiled Application

Figure 8. Performing User Actions over the Profiled Application

After the application is closed, the profiling session is over and AQtime generates results.

Note: It is also possible to capture the profiling results at any time during the profiling session by clicking the Get ResultsGet Results toolbar button or by selecting the Get Results menu item from AQtime's Run menu.

Analyzing Profiling Results

AQtime displays information obtained during the profiling session in several panels. The Summary panel displays general profiling results. It contains information on classes with the maximum number of existing instances, number of created objects and so on. The non-zero number of existing class instances indicates a memory leak.

Figure 9. General Profiling Results on the Summary Panel

Figure 9. General Profiling Results on the Summary Panel

Another panel, Report, displays information on leaked classes and objects. You select the desired result category in the Explorer panel on the left:

Figure 10. Classes Data and Objects Categories of the Results

Figure 10. Classes Data and Objects Categories of the Results

When we select the Classes Data category, the Report panel displays data on classes whose instances were created and on memory blocks that were allocated during the application run.

Figure 11. Looking for Leak Classes in the Allocation Profiler Results

Figure 11. Looking for Leak Classes in the Allocation Profiler Results

Take note of the Live Count column. It shows the number of class instances that were still living in memory after the application was closed. To find all such classes more quickly, sort the results in the Live Count column.

As you can see from the report, our sample application does not release several TBitmap, TBrush, TStringList and other objects, so we have memory leaks in it.


When the Objects category is selected, the Report panel shows information on each object or memory block that existed in memory at the moment the results were generated.

Figure 12. Looking for Leak Objects in the Allocation Profiler Results

Figure 12. Looking for Leak Objects in the Allocation Profiler Results

The Object name column contains identifiers for those objects and memory blocks.

Since we have several objects that still exist in memory after the application is terminated, we can say that there are memory leaks in our sample application.

Now let us find the source of those memory leaks and try to fix them.

Examining Application Call Stack and Modifying Source Code

AQtime allows us to view the call stack of functions that lead to the creation of leaked objects and examine the source code of the functions.

Viewing Call Stack When the Classes Data Category is Selected

In the Classes Data category we can view the call stack of functions that lead to creation of leaked class instances.

When the Classes Data category is selected, we enable the View Allocation Path in Call TreeView Allocation Path in Call Tree option (it allows displaying the hierarchy of function calls that led to creation of a class instance) and select the class instance whose call stack we want to examine.

The Call Tree panel at the bottom of the AQtime workspace now displays the tree view of the unreleased instance's functions call stack.

Figure 13. Viewing Call Stack for the Unreleased TBitmap Class

Figure 13. Viewing Call Stack for the Unreleased TBitmap Class

To find the routine that creates a leaked class instance, expand the tree nodes in the panel and explore the call stack tree. If the Live Count value of a routine is greater than zero, it means that the routine creates a leak class instance.

As we can see, in the call stack of the TBitmap class the Live Count value of the TObject.InitInstance routine is greater than zero, that is, it is the routine that creates instances of TBitmap leaked class.

However, this routine belongs to the System unit and is called to initialize data for an object in the constructor. We need to track the call stack tree upwards until we find the routine that belongs to our sample application module.

In our case it is the Create routine of the TBoard class that belongs to the UKnight.

Figure 14. TBoard.Create routine in the Call Stack

Figure 14. TBoard.Create routine in the Call Stack

We can switch to the Editor panel to analyze the source code of the TBoard.Create routine. But we will not do this right now and proceed with the viewing call stack for individual unreleased objects. We will view and analyze the application source code later in the article.

Important: AQtime only finds the module, routine and source code line where leaked objects are created. It cannot point out where these objects are leaked, that is, not freed properly. You can analyze the source code where the leaked objects are created and decide where in the code these objects should be released.

Viewing Call Stack for Individual Unreleased Objects and Analyzing the Application's Source Code

To view call stack information for individual objects, we select the Object category and choose the desired object in the Report panel.

The Creation Call Stack on the Details panel displays the stack of function calls that lead to leaked object creation. The topmost routine is the one that led to object creation.

It is the TObject.InitInstance routine that belongs to the System unit. We can neither view nor modify its source code. So we need to track down the call stack until we find the first routine that belongs to our sample application unit.

In our case it is the TBoard.Create routine that belongs to the UKnight unit.

Figure 15. Viewing Call Stack for the Leak TBitmap.310 Object

Figure 15. Viewing Call Stack for the Leak TBitmap.310 Object

Now let us examine the source code of the routine that creates the leaked object. To do it, we just need to double-click the desired routine in the call stack. If the path to the sample application sources is specified correctly, AQtime automatically switches to the Editor panel and highlights the desired routine.

Note: AQtime only finds source code lines of the routine that creates leaked objects. It does not specify where in the source code these leaked objects should be released.

Figure 16. Viewing the Source Code of the TBoard Class Constructor

Figure 16. Viewing the Source Code of the TBoard Class Constructor

In our case, the leaked objects are created in - the TBoard class constructor. By examining the code further, we can see that these objects are not destroyed anywhere.

Modifying the Application Code to Fix Memory Leaks.

To fix a leak, we need to release memory occupied by leaked objects. We will add the corresponding code to the TBoard class destructor:

destructor TBoard.Destroy;
{ Releases resources }
begin
  inherited Destroy;

  KnightBitmap.Free;
  CellBitmap.Free;
  SolutionsList.Free;
end;

Note: To implement this fix in the source project attached to the article, simply uncomment the {$DEFINE MemoryLeakFix} directive in the UKnight unit.

To confirm that this change indeed fixes the leak, we recompile the application and run memory profiling once again. As you can see, this time no leaks have been detected.

Figure 17. Looking for Live Objects in the General Allocation Profiler Results

Figure 17. Looking for Live Objects in the General Allocation Profiler Results

Conclusion

In this article we have demonstrated how you can detect memory leaks in native applications, pinpoint their source and confirm the fix. Download and try AQtime for memory profiling of your applications and see for yourself how to improve the application quality within minutes.