Introduction
I found out my code leaks memory of an instance of a TInterfacedObject that I keep as a Interface reference. Although I reset the reference variable to nil after usage, it remains alive.
The leaked object is of class TMasterObject, which implements two interfaces IInterfaceX and IInterfaceY. The object's reference is kept in a variable of type IInterfaceY.
TMasterObject's implementation of IInterfaceX is merely coincidental. Because it has two instances of TSomeObject, which requires a reference to this interface, I implemented it in TMasterObject as well.
MCVE / SSCCE
program InterfaceDependencies;
{$APPTYPE CONSOLE}
{$R *.res}
uses
System.SysUtils;
type
IInterfaceX = interface end;
IInterfaceY = interface end;
TSomeObject = class(TObject)
FReference: IInterfaceX;
constructor Create(AReferenceX: IInterfaceX);
end;
TMasterObject = class(TInterfacedObject, IInterfaceX, IInterfaceY)
FObjectA: TSomeObject;
FObjectB: TSomeObject;
constructor Create;
destructor Destroy; override;
end;
{ TSomeObject }
constructor TSomeObject.Create(AReferenceX: IInterfaceX);
begin
FReference := AReferenceX;
end;
{ TMasterObject }
constructor TMasterObject.Create;
begin
FObjectA := TSomeObject.Create(Self); // increments "FRefCount" by 1
FObjectB := TSomeObject.Create(Self); // increments "FRefCount" by 1
end;
destructor TMasterObject.Destroy;
begin
FObjectA.Free;
FObjectB.Free;
inherited;
end;
var
LMasterObject: IInterfaceY;
begin
try
LMasterObject := TMasterObject.Create;
// 'TMasterObject(LMasterObject).FRefCount' is now "3" because of 'FObjectA.FReference' and 'FObjectB.FReference'
LMasterObject := nil; // decrements 'TMasterObject(LMasterObject).FRefCount' by 1
// 'LMasterObject' is not destroyed because 'TMasterObject(LMasterObject).FRefCount' is still "2"
except
on E: Exception do
Writeln(E.ClassName, ': ', E.Message);
end;
end.
Question
What strategies can be used to
- solve this specific problem and
- avoid such problems in future?