Ceci est un exemple construit. Je ne veux pas poster le code original ici. J'ai essayé d'extraire les parties pertinentes cependant.Interfaces, méthodes anonymes et fuites de mémoire
J'ai une interface qui gère une liste d'écouteurs.
TListenerProc = reference to procedure (SomeInt : ISomeInterface);
ISomeInterface = interface
procedure AddListener (Proc : TListenerProc);
end;
Maintenant, j'enregistrer un écouteur:
SomeObj.AddListener (MyListener);
procedure MyListener (SomeInt : ISomeInterface);
begin
ExecuteSynchronized (procedure
begin
DoSomething (SomeInt);
end);
end;
Je reçois des fuites de mémoire. La méthode anonyme et les interfaces ne sont jamais libérées. Je soupçonne que cela est dû à une sorte de référence circulaire ici. La méthode anonyme maintient l'interface alife et l'interface maintient la méthode anonyme alife.
Deux questions:
- Approuvez-vous cette explication? Ou est-ce que je manque quelque chose d'autre ici?
- Y a-t-il quelque chose que je puisse faire à ce sujet?
Merci d'avance!
EDIT: Il est pas si facile de reproduire cela dans une application assez petit pour poster ici. Le mieux que je puisse faire maintenant est le suivant. La méthode anonyme n'est pas publiée ici:
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.
Vous devriez nous montrer comment fonctionne AddListener. –
Je les ai juste mis dans un 'TList.' –
jpfollenius
Tout le code que je vois a l'air bien. Le problème doit être dans la partie cachée. Pouvez-vous montrer un exemple complet qui produit la fuite? –