Einzelnen Beitrag anzeigen

Thom

Registriert seit: 19. Mai 2006
570 Beiträge
 
Delphi XE3 Professional
 
#10

AW: Speicherleck bei der Verwendung von anonymen Methoden

  Alt 16. Okt 2011, 17:10
@carlo93

Ohne einen überheblichen Ton kannst du wohl überhaupt nichts von dir geben?
Nö - das ist seine "nette" Art mit anderen umzugehen... Das findest Du in fast jedem seiner Beiträge.

Zu Deiner Frage:
Der Compiler speichert die von anonymen Methoden genutzen Variablen (Variablenbindung). Diese werden in TInterfacedObject-Derivaten mit Referenzzählung abgelegt.
Aus für mich nicht ersichtlichen Gründen besitzen diese Frames nach der Erstellung der anonymen Methode einen RefCount-Wert von 2. Nach Beendigung der Methode (in Deinem Fall TForm1.Create) wird dieser Wert wieder um zwei verringert und das Frame-Objekt aus dem Speicher entfernt. Tritt jetzt der Fall ein, das die anonyme Methode in einer anderen weiterverwendet wird, erhöht der Compiler RefCount des Frame-Objektes um eins und es wird beim Aufräumen am Ende der Methode nicht mehr gelöscht. So weit - so gut. Dummerweise verringert der Compiler in diesem Fall RefCount nur um eins und somit bleibt das Frame-Objekt auch zum Schluß erhalten. Meiner Meinung nach ist das ein Fehler im Compiler.
Da ich bei der Programmierung meines Frameworks auch auf dieses Problem gestoßen bin, habe ich dafür eine einfache Lösung entwickelt:
Delphi-Quellcode:
procedure TForm1.FormCreate(Sender: TObject);
var
  Func: TFunc<String>;
begin
  ReportMemoryLeaksOnShutdown:=true;
  Func:=
    function: String
    begin
      Result:=Edit1.Text;
    end;
  Memo1.Lines.Add(Func);
  FProc:=
    procedure
    begin
      Memo1.Lines.Add(Func);
    end;
  {$IF (CompilerVersion>=20) and (CompilerVersion<24)} //<- optimistisch ;-)
  if RefCount(Func)>2 //-> es existieren zusätzliche Referenzen
    then ReleaseMethod(Func); //<- RefCount wird um das fehlende Mal verringert
  {$IFEND}
end;
Lösungen:
- [...]
- [...]
- [...]
- [...]
- schmutzige Tricks, um diesen Fehler provisiorisch zu umgehn *1

1) IInterface(PPointer(@Func)^)._Release; als letzen Befehl in FormCreate,
aber sollte dieser Fehler wirklich mal irgendwann behoben werden, dann raucht dir die Anwendung ab.
Insofern entspricht das etwa himitsu's Lösung Nummer 5 mit vorherigem Test.
Delphi-Quellcode:
  {$IF (CompilerVersion>=20) and (CompilerVersion<???)} 
  if IInterface(PPointer(@Func)^)._AddRef>3
    then IInterface(PPointer(@Func)^)._Release;
  IInterface(PPointer(@Func)^)._Release;
  {$IFEND}
Thomas Nitzschke
Google Maps mit Delphi
  Mit Zitat antworten Zitat