Memory leaks 为什么此接口委派会导致内存泄漏?

Memory leaks 为什么此接口委派会导致内存泄漏?,memory-leaks,freepascal,Memory Leaks,Freepascal,假设我有以下代码 单位TalkerIntf.pas unit TalkerIntf; interface {$MODE OBJFPC} type ITalker = interface ['{95E1FAE3-7495-4404-AE88-6A7DB88383EC}'] procedure say() ; end; implementation end. unit TalkerImpl; interface {$MODE OBJFP

假设我有以下代码

单位TalkerIntf.pas

unit TalkerIntf;

interface

{$MODE OBJFPC}

type

    ITalker = interface
        ['{95E1FAE3-7495-4404-AE88-6A7DB88383EC}']
        procedure say() ;
    end;

implementation
end.
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;

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.
program memleak;

{$MODE OBJFPC}

uses

    TalkerIntf,
    TalkerImpl,
    DelegateTalkerImpl;

var
    talker : ITalker;

begin
    talker := TDelegateTalker.create(TTalker.create());
    talker.say();
end.
单位TalkerImpl.pas

unit TalkerIntf;

interface

{$MODE OBJFPC}

type

    ITalker = interface
        ['{95E1FAE3-7495-4404-AE88-6A7DB88383EC}']
        procedure say() ;
    end;

implementation
end.
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;

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.
program memleak;

{$MODE OBJFPC}

uses

    TalkerIntf,
    TalkerImpl,
    DelegateTalkerImpl;

var
    talker : ITalker;

begin
    talker := TDelegateTalker.create(TTalker.create());
    talker.say();
end.
单位DelegateTalkerImpl.pas

unit TalkerIntf;

interface

{$MODE OBJFPC}

type

    ITalker = interface
        ['{95E1FAE3-7495-4404-AE88-6A7DB88383EC}']
        procedure say() ;
    end;

implementation
end.
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;

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.
program memleak;

{$MODE OBJFPC}

uses

    TalkerIntf,
    TalkerImpl,
    DelegateTalkerImpl;

var
    talker : ITalker;

begin
    talker := TDelegateTalker.create(TTalker.create());
    talker.say();
end.
和程序memleak.pas

unit TalkerIntf;

interface

{$MODE OBJFPC}

type

    ITalker = interface
        ['{95E1FAE3-7495-4404-AE88-6A7DB88383EC}']
        procedure say() ;
    end;

implementation
end.
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;

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.
program memleak;

{$MODE OBJFPC}

uses

    TalkerIntf,
    TalkerImpl,
    DelegateTalkerImpl;

var
    talker : ITalker;

begin
    talker := TDelegateTalker.create(TTalker.create());
    talker.say();
end.
使用FreePascal 3.0.4和heaptrc on(
-gh
)编译时,heaptrc报告存在内存泄漏

$ fpc -gh memleak.pas
$ ./memleak
Heaptrc输出

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
为什么此接口委派会导致内存泄漏?如何避免呢

更新

似乎唯一的解决办法是删除
实现
并手动执行委派。以下代码没有内存泄漏

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.

将变量定义为ITalker时,不会返回新创建的对象,而只返回实现它的字段。结果,新创建的对象被泄漏。 德尔福的行为也是如此

为了避免内存泄漏,但仍然使用
implements
关键字,我们需要将其分配给类型不是
ITalker
的临时变量,然后将其键入
ITalker

var
    talker : ITalker;
    delegateTalker : IInterface;

begin
    delegateTalker := TDelegateTalker.create(TTalker.create());
    talker := delegateTalker as ITalker;
    talker.say();
end.

我认为这是fpc复制一个长期存在的Delphi错误的案例,它似乎永远不会被修复。