René Hoffmann
René Hoffmann

Reputation: 2815

memory leak when using TInterfacedObject as Interface reference in dependent objects

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

  1. solve this specific problem and
  2. avoid such problems in future?

Upvotes: 1

Views: 149

Answers (0)

Related Questions