to jest skonstruowany przykład. Nie chcę publikować oryginalnego kodu tutaj. Próbowałem jednak wyodrębnić odpowiednie części.Interfejsy, metody anonimowe i wycieki pamięci
Mam interfejs, który zarządza listą odbiorców.
TListenerProc = reference to procedure (SomeInt : ISomeInterface);
ISomeInterface = interface
procedure AddListener (Proc : TListenerProc);
end;
Teraz zarejestrować słuchacza:
SomeObj.AddListener (MyListener);
procedure MyListener (SomeInt : ISomeInterface);
begin
ExecuteSynchronized (procedure
begin
DoSomething (SomeInt);
end);
end;
ja rozumiem wycieków pamięci. Zarówno metoda anonimowa, jak i interfejsy nigdy nie są zwalniane. Podejrzewam, że wynika to z jakiegoś okrężnego odniesienia tutaj. Anonimowa metoda utrzymuje życie interfejsu, a interfejs utrzymuje anonimową metodę.
dwa pytania:
- Czy popierasz to wyjaśnienie? Czy może tu brakuje czegoś innego?
- Czy mogę coś z tym zrobić?
Z góry dziękuję!
EDIT: To nie jest tak łatwe do odtworzenia tego w aplikacji na tyle mały, aby opublikować go tutaj. Najlepsze, co mogę teraz zrobić, to: Anonimowa metoda nie jest dostępna tutaj:
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.
Pokażemy, jak działa AddListener. –
Po prostu umieszczam je w 'TList .' –
jpfollenius
Cały kod, który widzę, wygląda dobrze. Problem musi znajdować się w ukrytej części. Czy możesz pokazać pełny przykład, który powoduje wyciek? –