Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Why do interface implementations based on TComponent leak memory?

This Delphi code will show a memory leak for an instance of TMyImplementation:

program LeakTest;

uses
  Classes;

type
  MyInterface = interface
  end;

  TMyImplementation = class(TComponent, MyInterface)
  end;

  TMyContainer = class(TObject)
  private
    FInt: MyInterface;
  public
    property Impl: MyInterface read FInt write FInt;
  end;

var
  C: TMyContainer;
begin
  ReportMemoryLeaksOnShutdown := True;

  C := TMyContainer.Create;
  C.Impl := TMyImplementation.Create(nil);
  C.Free;
end.

If TComponent is replaced by TInterfacedObject and the constructor changed to Create(), the leak disappears. What is different with TComponent here?

Many thanks for the answers. To sum up: it is easy, but wrong, to say "If you are using interfaces, they are reference counted and hence they are freed for you." - Actually any class which implements an interface can break this rule. (And there will be no compiler hint or warning be shown.)

like image 477
mjn Avatar asked Feb 02 '10 08:02

mjn


1 Answers

Differences in implementation

  • TComponent._Release does not free your instance.
  • TInterfacedObject._Release does free your instance.

Perhaps someone can chime in but my take on this is that TComponent is not meant to be used as a reference counted object the way we normally use interfaces.

Implementation of TComponent._Release

function TComponent._Release: Integer;
begin
  if FVCLComObject = nil then
    Result := -1   // -1 indicates no reference counting is taking place
  else
    Result := IVCLComObject(FVCLComObject)._Release;
end;
like image 178
Lieven Keersmaekers Avatar answered Sep 20 '22 00:09

Lieven Keersmaekers