接口,匿名方法和内存泄漏

jpf*_*ius 17 delphi memory-management interface anonymous-methods delphi-2010

这是一个构造的例子.我不想在这里发布原始代码.我尝试提取相关部分.

我有一个管理监听器列表的界面.

TListenerProc = reference to procedure (SomeInt : ISomeInterface);

ISomeInterface = interface
   procedure AddListener (Proc : TListenerProc);   
end;
Run Code Online (Sandbox Code Playgroud)

现在我注册一个监听器:

SomeObj.AddListener (MyListener);

procedure MyListener (SomeInt : ISomeInterface);
begin
  ExecuteSynchronized (procedure
                       begin
                       DoSomething (SomeInt);
                       end);
end;
Run Code Online (Sandbox Code Playgroud)

我确实得到了内存泄漏.永远不会释放匿名方法和接口.我怀疑这是由于某种循环引用.匿名方法保持界面生效,界面保持匿名方法生效.

两个问题:

  1. 你支持这个解释吗?或者我在这里错过了其他什么?
  2. 我能做些什么吗?

提前致谢!


编辑:在一个小到足以在此发布的应用程序中重现这一点并不容易.我现在能做的最好的事情如下.匿名方法不会在这里发布:

program TestMemLeak;

{$APPTYPE CONSOLE}

uses
  Generics.Collections, SysUtils;

type
  ISomeInterface = interface;
  TListenerProc  = reference to procedure (SomeInt : ISomeInterface);

  ISomeInterface = interface
  ['{DB5A336B-3F79-4059-8933-27699203D1B6}']
    procedure AddListener (Proc : TListenerProc);
    procedure NotifyListeners;
    procedure Test;
  end;

  TSomeInterface = class (TInterfacedObject, ISomeInterface)
  strict private
    FListeners          : TList <TListenerProc>;
  protected
    procedure AddListener (Proc : TListenerProc);
    procedure NotifyListeners;
    procedure Test;
  public
    constructor Create;
    destructor  Destroy; override;
  end;


procedure TSomeInterface.AddListener(Proc: TListenerProc);
begin
FListeners.Add (Proc);
end;

constructor TSomeInterface.Create;
begin
FListeners := TList <TListenerProc>.Create;
end;

destructor TSomeInterface.Destroy;
begin
FreeAndNil (FListeners);
  inherited;
end;

procedure TSomeInterface.NotifyListeners;

var
  Listener : TListenerProc;

begin
for Listener in FListeners do
  Listener (Self);
end;

procedure TSomeInterface.Test;
begin
// do nothing
end;

procedure Execute (Proc : TProc);

begin
Proc;
end;

procedure MyListener (SomeInt : ISomeInterface);
begin
Execute (procedure
         begin
         SomeInt.Test;
         end);
end;

var
  Obj     : ISomeInterface;

begin
  try
    ReportMemoryLeaksOnShutdown := True;
    Obj := TSomeInterface.Create;
    Obj.AddListener (MyListener);
    Obj.NotifyListeners;
    Obj := nil;
  except
    on E: Exception do
      Writeln(E.ClassName, ': ', E.Message);
  end;
end.
Run Code Online (Sandbox Code Playgroud)

mgh*_*hie 8

你的代码远远不是最小的.下列:

program AnonymousMemLeak;

{$APPTYPE CONSOLE}

uses
  SysUtils;

type
  TListenerProc  = reference to procedure (SomeInt : IInterface);

procedure MyListener (SomeInt : IInterface);
begin
end;

var
  Listener: TListenerProc;

begin
  try
    ReportMemoryLeaksOnShutdown := True;

    Listener := MyListener;
    Listener := nil;
  except
    on E: Exception do
      Writeln(E.ClassName, ': ', E.Message);
  end;
end.
Run Code Online (Sandbox Code Playgroud)

有同样的问题(这里是Delphi 2009).这不能工作或设计.看起来像编译器中的错误.

编辑:

或者这可能是内存泄漏检测的问题.它与作为接口的参数无关,无参数的过程导致相同的"泄漏".很奇怪.