Understanding and Preventing Memory Leaks

Memory Card Brain
Getty Images/AustinArtist

Delphi's support for object-oriented programming is rich and powerful. Classes and objects allow for modular code programming. Along with more modular and more complex components come more sophisticated and more complex bugs.

While developing applications in Delphi is (almost) always fun, there are situations when you feel like the whole world is against you.

Whenever you need to use (create) an object in Delphi, you need to free the memory it consumed (once no longer needed). Surely, the try/finally memory guarding blocks can help you prevent memory leaks; it's still up to you to safeguard your code.

A memory (or resource) leak occurs when the program loses the ability to free the memory it consumes. Repeated memory leaks cause the memory usage of a process to grow without bounds. Memory leaks are a serious problem -- if you have a code causing memory leak, in an application running 24/7, the application will eat up all the memory available and finally make the machine stop responding.

Memory Leaks in Delphi

The first step to avoiding memory leaks is to understand how they occur. What follows is a discussion on some common pitfalls and best practices for writing non-leaking Delphi code.

In most (simple) Delphi applications, where you use the components (Buttons, Memos, Edits, etc.) you drop on a form (at design time), you do not need to care too much about memory management. Once the component is placed on a form, the form becomes its owner and will free the memory taken by the component once the form is closed (destroyed). Form, as the owner, is responsible for memory deallocation of the components it hosted. In short: components on a form are created and destroyed automatically

A simple memory leak example: In any non-trivial Delphi application, you will want to instantiate Delphi components at run time. You will, also, have some of your own custom classes. Let's say you have a class TDeveloper that has a method DoProgram. Now, when you need to use the TDeveloper class, you create an instance of the class by calling the Create method (constructor). The Create method allocates memory for a new object and returns a reference to the object.

var
   zarko : TDeveloper
begin
   zarko := TMyObject.Create;
   zarko.DoProgram;
end;

And here's a simple memory leak!

Whenever you create an object, you must dispose of the memory it occupied. To free the memory an object allocated, you must call the Free method. To be perfectly sure, you should also use the try / finally block:

var
   zarko : TDeveloper
begin
   zarko := TMyObject.Create;
   try
    zarko.DoProgram;
   finally
     zarko.Free;
   end;
end;

This is an example of a safe memory allocation and deallocation code.

Some words of warning: If you want to dynamically instantiate a Delphi component and explicitly free it sometime later, always pass nil as the owner. Failure to do so can introduce unnecessary risk, as well as performance and code maintenance problems.

A simple resource leak example: Besides creating and destroying objects using the Create and Free methods, you must also be very careful when using "external" (files, databases, etc) resources.
Let's say you need to operate on some text file. In a very simple scenario, where the AssignFile method is used to associate a file on a disk with a file variable when you are finished with the file, you must call CloseFile to free the file handle begin used. This is where you do not have an explicit call to "Free".

var
   F: TextFile;
   S: string;
begin
   AssignFile(F, 'c:\somefile.txt') ;
   try
     Readln(F, S) ;
   finally
     CloseFile(F) ;
   end;
end;

Another example includes loading external DLLs from your code. Whenever you use LoadLibrary, you must call FreeLibrary:

var
   dllHandle : THandle;
begin
   dllHandle := Loadlibrary('MyLibrary.DLL') ;
   //do something with this DLL
   if dllHandle <> 0 then FreeLibrary(dllHandle) ;
end;

Memory Leaks in .NET?

Although with Delphi for .NET the garbage collector (GC) manages most memory tasks, it is possible to have memory leaks in .NET applications. Here's an article discussion GC in Delphi for .NET.

How to Fight Against Memory Leaks

Besides writing modular memory-safe code, preventing memory leaks can be done by using some of the third-party tools available. Delphi Memory Leak Fix Tools help you catch Delphi application errors such as memory corruption, memory leaks, memory allocation errors, variable initialization errors, variable definition conflicts, pointer errors, and more.