Suppose I have following codes
Unit TalkerIntf.pas
unit TalkerIntf;
interface
{$MODE OBJFPC}
type
ITalker = interface
['{95E1FAE3-7495-4404-AE88-6A7DB88383EC}']
procedure say() ;
end;
implementation
end.
Unit TalkerImpl.pas
unit TalkerImpl;
interface
{$MODE OBJFPC}
uses
TalkerIntf;
type
TTalker = class(TInterfacedObject, ITalker)
public
procedure say();
end;
implementation
procedure TTalker.say();
begin
writeln('Hello');
end;
end.
Unit DelegateTalkerImpl.pas
unit DelegateTalkerImpl;
interface
{$MODE OBJFPC}
uses
TalkerIntf;
type
TDelegateTalker = class(TInterfacedObject, ITalker)
private
fActualTalker : ITalker;
public
constructor create(const talker : ITalker);
destructor destroy(); override;
property talker : ITalker read fActualTalker implements ITalker;
end;
implementation
constructor TDelegateTalker.create(const talker : ITalker);
begin
fActualTalker := talker;
end;
destructor TDelegateTalker.destroy();
begin
fActualTalker := nil;
inherited destroy();
end;
end.
and program memleak.pas
program memleak;
{$MODE OBJFPC}
uses
TalkerIntf,
TalkerImpl,
DelegateTalkerImpl;
var
talker : ITalker;
begin
talker := TDelegateTalker.create(TTalker.create());
talker.say();
end.
Compiling with FreePascal 3.0.4 and heaptrc on (-gh
), heaptrc reports there are memory leak
$ fpc -gh memleak.pas
$ ./memleak
Heaptrc output
Hello
Heap dump by heaptrc unit
2 memory blocks allocated : 64/64
0 memory blocks freed : 0/0
2 unfreed memory blocks : 64
True heap size : 32768
True free heap : 32384
Should be : 32448
Call trace for block $00007FA0D7846180 size 32
$000000000040020F
Call trace for block $00007FA0D78460C0 size 32
Why is this interface delegation causing memory leak? How to avoid it?
Update
It seems the only workaround is remove implements
and do delegation manually. Following code does not suffer from memory leak.
unit DelegateTalkerImpl;
interface
{$MODE OBJFPC}
uses
TalkerIntf;
type
TDelegateTalker = class(TInterfacedObject, ITalker)
private
fActualTalker : ITalker;
public
constructor create(const talker : ITalker);
destructor destroy(); override;
procedure say();
end;
implementation
constructor TDelegateTalker.create(const talker : ITalker);
begin
fActualTalker := talker;
end;
destructor TDelegateTalker.destroy();
begin
fActualTalker := nil;
inherited destroy();
end;
procedure TDelegateTalker.say();
begin
fActualTalker.say();
end;
end.