I’ve been tracking down some memory leaks in a program written in the Delphi language (formerly known as Borland’s Object Pascal). I’ve run across this a few times over the years.
Interfaced objects in Delphi have the wonderful benefit of automatic lifetime management due to automatic reference counting. It’s almost as convenient as the automatic object disposal Java, C#, and Objective C (on Mac OS X Leopard).
There’s a potential memory leak, however if you descend from TInterfacedObject and override the AfterConstruction method. You must call inherited else the object will never be released!
How This Happens
Note that the constructor increments the reference count otherwise it will go to zero during construction under certain circumstances. That, of course, would cause the object to free itself immediately… and you the programmer would go an a man hunt to avenge the accelerated hair loss.
Because the constructor increases the reference count to prevent premature destruction, the reference count must also be decreased to its correct value after the constructor has finished executing. This happens in the AfterConstruction method. Look at the implementation in System.pas:
procedure TInterfacedObject.AfterConstruction; begin // Release the constructor's implicit refcount InterlockedDecrement(FRefCount); end;
Say you descend from TInterfacedObject, and do something in AfterConstruction. The following example is simplistic, but makes the case:
type IFoo = interface end; TFoo = class(TInterfacedObject, IFoo) private Bar :Integer; public procedure AfterConstruction; override; end; . . . TFoo.AfterConstruction; begin Bar := 1; end;
Note that TFoo.AfterConstruction does not call inherited. Because inherited is not called, TInterfacedObject.AfterConstruction is not called, and the implicit reference count done in the constructor will never be undone.
Thus, the following code will never release the instance of TFoo:
var lFoo :IFoo; begin lFoo := TFoo.Create; end;
To fix this memory leak, call inherited in the descendant’s AfterConstruction definition, thus:
TFoo.AfterConstruction; begin inherited; // <---- CALL inherited HERE! Bar := 1; end;