AGB  ·  Datenschutz  ·  Impressum  







Anmelden
Nützliche Links
Registrieren
Zurück Delphi-PRAXiS Sprachen und Entwicklungsumgebungen Object-Pascal / Delphi-Language Delphi Speicherleck bei der Verwendung von anonymen Methoden
Thema durchsuchen
Ansicht
Themen-Optionen

Speicherleck bei der Verwendung von anonymen Methoden

Ein Thema von carlo93 · begonnen am 15. Okt 2011 · letzter Beitrag vom 4. Nov 2011
Antwort Antwort
Seite 1 von 3  1 23      
carlo93

Registriert seit: 15. Okt 2011
3 Beiträge
 
#1

Speicherleck bei der Verwendung von anonymen Methoden

  Alt 15. Okt 2011, 23:40
Delphi-Version: XE
Hallo!

Folgendes Problem:

Bei der Verwendung dieses Quelltextes entsteht ein Speicherleck:
Delphi-Quellcode:
type
  TForm1 = class(TForm)
    Memo1: TMemo;
    Panel1: TPanel;
    Button1: TButton;
    Edit1: TEdit;
    procedure FormCreate(Sender: TObject);
    procedure FormDestroy(Sender: TObject);
    procedure Button1Click(Sender: TObject);
  private
    FProc: TProc;
  public
    { Public-Deklarationen }
  end;

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

procedure TForm1.Button1Click(Sender: TObject);
begin
  FProc;
end;
screenshot.jpg

Momentan kann ich leider nicht überprüfen, ob das auch bei XE2 auftritt (meine Testversion ist gerade abgelaufen).
Gibt es eine Möglichkeit, dieses Speicherleck zu verhindern?
  Mit Zitat antworten Zitat
Benutzerbild von jaenicke
jaenicke

Registriert seit: 10. Jun 2003
Ort: Berlin
9.648 Beiträge
 
Delphi 11 Alexandria
 
#2

AW: Speicherleck bei der Verwendung von anonymen Methoden

  Alt 16. Okt 2011, 10:38
Umgehen lässt sich das Problem leicht:
Mach aus Func auch ein privates Feld statt einer lokalen Variable.

Schöner ist aber wohl diese Lösung:
Delphi-Quellcode:
procedure TForm142.FormCreate(Sender: TObject);

  procedure DoInit(Func: TFunc<String>);
  begin
    Memo1.Lines.Add(Func);
    FProc :=
      procedure
      begin
        Memo1.Lines.Add(Func);
      end;
  end;

begin
  ReportMemoryLeaksOnShutdown := true;
  DoInit(function: String
    begin
      Result := Edit1.Text;
    end);
end;
Sebastian Jänicke
AppCentral
  Mit Zitat antworten Zitat
Benutzerbild von himitsu
himitsu

Registriert seit: 11. Okt 2003
Ort: Elbflorenz
44.184 Beiträge
 
Delphi 12 Athens
 
#3

AW: Speicherleck bei der Verwendung von anonymen Methoden

  Alt 16. Okt 2011, 10:49
Da wird wohl die eingebetette Reference nicht mehr freigegeben.

Am Generic liegt es nicht, dann wenn man TFunc<String> durch einen richtigen Typen ersetzt, ändert sich nichts.


Lösungen:
- im QC melden und hoffen es wird eventuell irgendwann in den nächsten Jahrzehnten behoben
- auf verschachtelte Referencen verzichten
- oder Func ebenfalls als privates FFunc in der Form speichern [add] wie schonmal genannt
- diesen Fehler einfach ignorieren (wird ja eh nie behoben)
- 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.
$2B or not $2B

Geändert von himitsu (16. Okt 2011 um 10:55 Uhr)
  Mit Zitat antworten Zitat
Benutzerbild von jaenicke
jaenicke

Registriert seit: 10. Jun 2003
Ort: Berlin
9.648 Beiträge
 
Delphi 11 Alexandria
 
#4

AW: Speicherleck bei der Verwendung von anonymen Methoden

  Alt 16. Okt 2011, 12:08
Gerade getestet: Das Problem tritt auch bei XE2 noch auf.
Sebastian Jänicke
AppCentral
  Mit Zitat antworten Zitat
Benutzerbild von Bernhard Geyer
Bernhard Geyer

Registriert seit: 13. Aug 2002
17.202 Beiträge
 
Delphi 10.4 Sydney
 
#5

AW: Speicherleck bei der Verwendung von anonymen Methoden

  Alt 16. Okt 2011, 12:19
Tritt das Speicherleck bei jeder verwendung auf oder einmalig beim ersten Aufruf?
Windows Vista - Eine neue Erfahrung in Fehlern.
  Mit Zitat antworten Zitat
Benutzerbild von jaenicke
jaenicke

Registriert seit: 10. Jun 2003
Ort: Berlin
9.648 Beiträge
 
Delphi 11 Alexandria
 
#6

AW: Speicherleck bei der Verwendung von anonymen Methoden

  Alt 16. Okt 2011, 12:21
Einmal, es wird ja schließlich die Funktion nicht freigegeben und die existiert nun einmal nur einmal...

// EDIT:
Bzw. wenn man den Code aus FormCreate mehrfach ausführt, wird natürlich bei jeder Ausführung ein Speicherleck produziert.
Sebastian Jänicke
AppCentral

Geändert von jaenicke (16. Okt 2011 um 12:24 Uhr)
  Mit Zitat antworten Zitat
Benutzerbild von Stevie
Stevie

Registriert seit: 12. Aug 2003
Ort: Soest
4.027 Beiträge
 
Delphi 10.1 Berlin Enterprise
 
#7

AW: Speicherleck bei der Verwendung von anonymen Methoden

  Alt 16. Okt 2011, 16:13
Ist schon lange bekannt: QC #83259 und QC #78066.

Tip: Wenn ihr beschleunigen wollt, dass bestimmte Einträge gefixt werden, dann nutzt die Vote Funktion (man kann entgegen dem Irrglauben einiger pro Eintrag 10 Punkte vergeben).
Stefan
“Simplicity, carried to the extreme, becomes elegance.” Jon Franklin

Delphi Sorcery - DSharp - Spring4D - TestInsight

Geändert von Stevie (16. Okt 2011 um 16:16 Uhr)
  Mit Zitat antworten Zitat
carlo93

Registriert seit: 15. Okt 2011
3 Beiträge
 
#8

AW: Speicherleck bei der Verwendung von anonymen Methoden

  Alt 16. Okt 2011, 16:29
@jaenicke

Vielen Dank für's Testen und die nette Antwort!

Ist schon lange bekannt
@Stevie

Ich hatte nicht gefragt, ob das Problem bekannt ist, sondern
  1. ob das Problem unter XE2 auch noch auftritt und
  2. ob es dafür (schon) eine Lösung gibt.

Ohne einen überheblichen Ton kannst du wohl überhaupt nichts von dir geben?
  Mit Zitat antworten Zitat
Benutzerbild von Stevie
Stevie

Registriert seit: 12. Aug 2003
Ort: Soest
4.027 Beiträge
 
Delphi 10.1 Berlin Enterprise
 
#9

AW: Speicherleck bei der Verwendung von anonymen Methoden

  Alt 16. Okt 2011, 16:48
Ohne einen überheblichen Ton kannst du wohl überhaupt nichts von dir geben?
Ich habe lediglich darauf hingewiesen, dass das Problem bekannt und nicht gefixt ist.
Da der Eintrag nicht geclosed ist, tritt der Bug noch in XE2 auf (1.)
Wenn du dir die Einträge anschaust, siehst du woran das Problem liegt und auch Workarounds (2.)

Im übrigen wurde hier in diesem Thread darauf hingewiesen, einen QC Eintrag zu machen - daher habe ich mir die Mühe gemacht, das mal nachzuschauen.

Wenn du Sachlichkeit mit Überheblichkeit verwechselst, tut's mir leid für dich.
Stefan
“Simplicity, carried to the extreme, becomes elegance.” Jon Franklin

Delphi Sorcery - DSharp - Spring4D - TestInsight

Geändert von Stevie (16. Okt 2011 um 16:56 Uhr)
  Mit Zitat antworten Zitat
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, 18: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
Antwort Antwort
Seite 1 von 3  1 23      


Forumregeln

Es ist dir nicht erlaubt, neue Themen zu verfassen.
Es ist dir nicht erlaubt, auf Beiträge zu antworten.
Es ist dir nicht erlaubt, Anhänge hochzuladen.
Es ist dir nicht erlaubt, deine Beiträge zu bearbeiten.

BB-Code ist an.
Smileys sind an.
[IMG] Code ist an.
HTML-Code ist aus.
Trackbacks are an
Pingbacks are an
Refbacks are aus

Gehe zu:

Impressum · AGB · Datenschutz · Nach oben
Alle Zeitangaben in WEZ +1. Es ist jetzt 06:13 Uhr.
Powered by vBulletin® Copyright ©2000 - 2024, Jelsoft Enterprises Ltd.
LinkBacks Enabled by vBSEO © 2011, Crawlability, Inc.
Delphi-PRAXiS (c) 2002 - 2023 by Daniel R. Wolf, 2024 by Thomas Breitkreuz