Heaptrace
Heaptrace
Hallo,
ich bin auf der Suche nach memleaks und habe nun die heaptrace - Unit mit einkompiliert.
Nun wirft mir der Debugger beim beenden seitenweise Meldungen raus, mit denen ich im 1. Schritt wenig anfangen kann.
Gibt es irgentwo eine Doku zu heaptrace?
Gruß
Kernel
ich bin auf der Suche nach memleaks und habe nun die heaptrace - Unit mit einkompiliert.
Nun wirft mir der Debugger beim beenden seitenweise Meldungen raus, mit denen ich im 1. Schritt wenig anfangen kann.
Gibt es irgentwo eine Doku zu heaptrace?
Gruß
Kernel
Re: Heaptrace
http://www.lazarus.freepascal.org/index ... pic=8362.0" onclick="window.open(this.href);return false;
-
carli
- Beiträge: 657
- Registriert: Sa 9. Jan 2010, 17:32
- OS, Lazarus, FPC: Linux 2.6.x, SVN-Lazarus, FPC 2.4.0-2
- CPU-Target: 64Bit
Re: Heaptrace
Die seitenweise Meldungen sind eigentlich einfach zu verstehen:
Jeder Block "Meldungen" ist ein Stacktrace, an welcher Stelle Speicher allokiert wurde.
d.h. du suchst dir die erste Zeile jedes Blockes, entnimmst die Zeilennummer und die Datei (Compilereinstellung: Zeilennummern mit hineinkompilieren) und siehst genau die Stelle, wo Speicher herkommt, den du nicht freigegeben hast.
Klar, viele Blöcke doppeln sich, da eine Allokation ja nicht nur einmal gemacht wurde. Sinnvoll ist es, erst mal den einen Leck zu fixen und dann zu schauen, wieviel Fehlermeldungen dann übrig bleiben
Jeder Block "Meldungen" ist ein Stacktrace, an welcher Stelle Speicher allokiert wurde.
d.h. du suchst dir die erste Zeile jedes Blockes, entnimmst die Zeilennummer und die Datei (Compilereinstellung: Zeilennummern mit hineinkompilieren) und siehst genau die Stelle, wo Speicher herkommt, den du nicht freigegeben hast.
Klar, viele Blöcke doppeln sich, da eine Allokation ja nicht nur einmal gemacht wurde. Sinnvoll ist es, erst mal den einen Leck zu fixen und dann zu schauen, wieviel Fehlermeldungen dann übrig bleiben
Re: Heaptrace
Danke für Eure Antworten!
Ich bekomme im Output über 100 Einträge, aber 90% scheinen sich im Endeffekt auf FPC/Lazarus - Code zu beziehen?!
Oder z.B. hier:
Das o.g. ist die Zuweisung eines Events!
Was soll ich denn da wieder freigeben?
Ist das normal?
Gruß
Kernel
Ich bekomme im Output über 100 Einträge, aber 90% scheinen sich im Endeffekt auf FPC/Lazarus - Code zu beziehen?!
Oder z.B. hier:
Code: Alles auswählen
Call trace for block $B6FA5E60 size 48
$080928F4 TMAINFORM__FORMCREATE, line 1091 of main.pas
$08081F23 TCUSTOMFORM__DOCREATE, line 870 of ./include/customform.inc
$080805E7 TCUSTOMFORM__AFTERCONSTRUCTION, line 79 of ./include/customform.inc
$080868FE TFORM__CREATE, line 2865 of ./include/customform.inc
$0808DE18 TAPPLICATION__CREATEFORM, line 2084 of ./include/application.inc
$0805D7E7 main, line 27 of proj443.lpr
$083B840DWas soll ich denn da wieder freigeben?
Ist das normal?
Gruß
Kernel
- corpsman
- Lazarusforum e. V.
- Beiträge: 1676
- Registriert: Sa 28. Feb 2009, 08:54
- OS, Lazarus, FPC: Linux Mint Mate, Lazarus GIT Head, FPC 3.0
- CPU-Target: 64Bit
- Wohnort: Stuttgart
- Kontaktdaten:
Re: Heaptrace
Also für mich sieht das so aus wie wenn du in deiner Tform1.create
jede menge Variablen erstellst ( mit New, oder xy := TXy.create )
sie aber nie wieder frei gibst.
Versuche mal in TForm1.destroy alle Variable die du in Create erzeugt hast wieder frei zu geben.
jede menge Variablen erstellst ( mit New, oder xy := TXy.create )
sie aber nie wieder frei gibst.
Versuche mal in TForm1.destroy alle Variable die du in Create erzeugt hast wieder frei zu geben.
--
Just try it
Just try it
Re: Heaptrace
Nein, so einfach ist es nichtAlso für mich sieht das so aus wie wenn du in deiner Tform1.create
jede menge Variablen erstellst ( mit New, oder xy := TXy.create )
sie aber nie wieder frei gibst.
Versuche mal in TForm1.destroy alle Variable die du in Create erzeugt hast wieder frei zu geben.
An der Stelle im Code, auf welchen die Ausgabe verweist stehlt sowas wie Obj.OnEvent := @HandleEvent;
Alle Objects, welche ich Erzeuge werden auch in Destroy freigegeben. (Zumindest geplant)
Aber die Fülle der Meldungen, überrascht mich, da viele der Meldungen gar nicht aus meinem Code kommen, sondern aus der lcl, etc...
Gruß
Kernel
-
carli
- Beiträge: 657
- Registriert: Sa 9. Jan 2010, 17:32
- OS, Lazarus, FPC: Linux 2.6.x, SVN-Lazarus, FPC 2.4.0-2
- CPU-Target: 64Bit
Re: Heaptrace
2 Sachen, die man beachten sollte:
- hast du jeden destructor destroy; mit "override" markiert?
- hast du in jeden constructor und destructor "inherited" aufgerufen?
Die LCL hat eine Klasse namens TComponent, die sich u.a. um das Aufräumen des Speichers kümmert. Wenn man diese Funktion aushebelt, kommt es wie immer zu "unwished results"
(ich mag diese Bezeichnung und finde keine treffendere deutsche Bezeichnung dafür)
- hast du jeden destructor destroy; mit "override" markiert?
- hast du in jeden constructor und destructor "inherited" aufgerufen?
Die LCL hat eine Klasse namens TComponent, die sich u.a. um das Aufräumen des Speichers kümmert. Wenn man diese Funktion aushebelt, kommt es wie immer zu "unwished results"
- m.fuchs
- Lazarusforum e. V.
- Beiträge: 2868
- Registriert: Fr 22. Sep 2006, 19:32
- OS, Lazarus, FPC: Winux (Lazarus 2.0.10, FPC 3.2.0)
- CPU-Target: x86, x64, arm
- Wohnort: Berlin
- Kontaktdaten:
Re: Heaptrace
Das kommt schon aus deinem Code. Mach mal ein neues Testprojekt mit einem leerem Formular. Im OnCreate dieses Form machst du mal folgendes:Kernel hat geschrieben:Aber die Fülle der Meldungen, überrascht mich, da viele der Meldungen gar nicht aus meinem Code kommen, sondern aus der lcl, etc...
Code: Alles auswählen
procedure TForm1.FormCreate(Sender: TObject);
var
x: TObject;
begin
x := TObject.Create;
end;Und schau dir dann mal die heaptrace - Ausgabe an. Kleiner Hinweis: Das ist ein call trace, er zeigt welche Aufrufe im Programm ablaufen. Dein Trace von oben sagt dir:
Code: Alles auswählen
Call trace for block $B6FA5E60 size 48
[color=#FF0000]In Zeile 1091 der main.pas wird etwas erzeugt, was nicht weggeräumt wurde. Das ist passiert als die Prozedur [b]FormCreate[/b] aufgerufen wurde.[/color]
$080928F4 TMAINFORM__FORMCREATE, line 1091 of main.pas
[color=#FF0000]Der Aufruf von [b]FormCreate[/b] kam von der Prozedur [b]DoCreate[/b].[/color]
$08081F23 TCUSTOMFORM__DOCREATE, line 870 of ./include/customform.inc
[color=#FF0000]Der Aufruf von [b]DoCreate[/b] kam von der Prozedur [b]AfterConstruction[/b][/color]
$080805E7 TCUSTOMFORM__AFTERCONSTRUCTION, line 79 of ./include/customform.inc
[color=#FF0000]Der Aufruf von [b]AfterConstruction[/b] kam von der Prozedur [b]Create[/b][/color]Letztendlich steckt der Fehler in Zeile 1091 deiner main.pas. Der call trace dient nur dazu, dass du nachvollziehen kannst, wie diese Zeile durch was aufgerufen wurde.
Wenn du sagst, dass du über 100 Einträge bekommst: was ist für dich ein Eintrag? Genauer gefragt: Ist der von dir eingefügte call trace ein Eintrag oder sechs? Wenn letzteres zutrifft hast du nicht so viele Probleme wie du denkst. Nach Beseitigung des Problems aus Zeile 1091 sind dann nämlich schon sechs Probleme weg.
0118999881999119725-3
Software, Bibliotheken, Vorträge und mehr: https://www.ypa-software.de
Software, Bibliotheken, Vorträge und mehr: https://www.ypa-software.de
Re: Heaptrace
Hallo,
also Destructor public, override und inherited habe ich natürlich drin.
Das mit dem Call-Stack hatte ich auch so verstanden.
Leider sind es hunderte Blöcke und nicht einzelner Einträge.
Als Beispiel:
Call trace for block $B70DE220 size 20
$08147D56 TRASTERIMAGE__LOADFROMSTREAM, line 442 of ./include/rasterimage.inc
$081594C2 TBITMAP__LOADFROMSTREAM, line 148 of ./include/bitmap.inc
$08148E13 TRASTERIMAGE__READDATA, line 900 of ./include/rasterimage.inc
$081464D5 TPICTURE__READDATA, line 759 of ./include/picture.inc
$080F49A7
$081466AA TPICTURE__DEFINEPROPERTIES, line 808 of ./include/picture.inc
$080F63BE
$080F57EB
hier ist nicht eine Zeile meines Codes im Call-Stack...
Gruß
Kernel
also Destructor public, override und inherited habe ich natürlich drin.
Das mit dem Call-Stack hatte ich auch so verstanden.
Leider sind es hunderte Blöcke und nicht einzelner Einträge.
Als Beispiel:
Call trace for block $B70DE220 size 20
$08147D56 TRASTERIMAGE__LOADFROMSTREAM, line 442 of ./include/rasterimage.inc
$081594C2 TBITMAP__LOADFROMSTREAM, line 148 of ./include/bitmap.inc
$08148E13 TRASTERIMAGE__READDATA, line 900 of ./include/rasterimage.inc
$081464D5 TPICTURE__READDATA, line 759 of ./include/picture.inc
$080F49A7
$081466AA TPICTURE__DEFINEPROPERTIES, line 808 of ./include/picture.inc
$080F63BE
$080F57EB
hier ist nicht eine Zeile meines Codes im Call-Stack...
Gruß
Kernel
- m.fuchs
- Lazarusforum e. V.
- Beiträge: 2868
- Registriert: Fr 22. Sep 2006, 19:32
- OS, Lazarus, FPC: Winux (Lazarus 2.0.10, FPC 3.2.0)
- CPU-Target: x86, x64, arm
- Wohnort: Berlin
- Kontaktdaten:
Re: Heaptrace
Das sind mit Sicherheit Seiteneffekte deines Codes. Wenn ich meine Glaskugel benutzen würde, würde ich behaupten: Irgendwie wird ein TPicture erzeugt. Irgendwo werden Daten in dieses TPicture geladen. Und nirgendwo wird dieses TPicture wieder zerstört.Kernel hat geschrieben:Call trace for block $B70DE220 size 20
$08147D56 TRASTERIMAGE__LOADFROMSTREAM, line 442 of ./include/rasterimage.inc
$081594C2 TBITMAP__LOADFROMSTREAM, line 148 of ./include/bitmap.inc
$08148E13 TRASTERIMAGE__READDATA, line 900 of ./include/rasterimage.inc
$081464D5 TPICTURE__READDATA, line 759 of ./include/picture.inc
$080F49A7
$081466AA TPICTURE__DEFINEPROPERTIES, line 808 of ./include/picture.inc
$080F63BE
$080F57EB
hier ist nicht eine Zeile meines Codes im Call-Stack...
Mit folgendem Code, kriege ich auch ellenlange call traces:
Code: Alles auswählen
procedure TForm1.FormCreate(Sender: TObject);
var
x: TPicture;
begin
x := TPicture.Create;
x.LoadFromFile('project1.ico');
end;Ist natürlich alles ein bisschen nervig, aber mit ein bisschen Disziplin und Sucherei findet man auch dieses Speicherbereinigungsprobleme.
BTW: Die andere Lösung (Garbage Collector) ist übrigens auch net so toll. Wir quälen uns auf Arbeit immer mal wieder mit dem .NET GC herum, der es nicht schafft die Objekte wirklich dann wegzuräumen wenn wir das wollen.
0118999881999119725-3
Software, Bibliotheken, Vorträge und mehr: https://www.ypa-software.de
Software, Bibliotheken, Vorträge und mehr: https://www.ypa-software.de
Re: Heaptrace
Ich danke auf jeden Fall für die Antworten und bin schon dabei alle erkannten Leaks zu beheben.
Mal sehen was übrig bleibt.
btw: macht es in diesem Bezug wirklich einen Unterschied ob der Destructor public ist, oder nicht?
Also
oder
Mal sehen was übrig bleibt.
btw: macht es in diesem Bezug wirklich einen Unterschied ob der Destructor public ist, oder nicht?
Also
Code: Alles auswählen
TMyObj = class(Tobject)
destructor destroy;override;
End;Code: Alles auswählen
TMyObj = class(Tobject)
public
destructor destroy;override;
End;- m.fuchs
- Lazarusforum e. V.
- Beiträge: 2868
- Registriert: Fr 22. Sep 2006, 19:32
- OS, Lazarus, FPC: Winux (Lazarus 2.0.10, FPC 3.2.0)
- CPU-Target: x86, x64, arm
- Wohnort: Berlin
- Kontaktdaten:
Re: Heaptrace
AFAIK kann man die Sichtbarkeit in abgeleiteten Klassen nicht verringern. Da Destroy in TObject als public definiert ist, ist es in das auch in obigen Code. Wichtig ist override und der inherited Aufruf am Ende deines Destructor-Codes.Kernel hat geschrieben:btw: macht es in diesem Bezug wirklich einen Unterschied ob der Destructor public ist, oder nicht?
Also
Code: Alles auswählen
TMyObj = class(Tobject) destructor destroy;override; End;
0118999881999119725-3
Software, Bibliotheken, Vorträge und mehr: https://www.ypa-software.de
Software, Bibliotheken, Vorträge und mehr: https://www.ypa-software.de
-
Socke
- Lazarusforum e. V.
- Beiträge: 3178
- Registriert: Di 22. Jul 2008, 19:27
- OS, Lazarus, FPC: Lazarus: SVN; FPC: svn; Win 10/Linux/Raspbian/openSUSE
- CPU-Target: 32bit x86 armhf
- Wohnort: Köln
- Kontaktdaten:
Re: Heaptrace
Man kann es zumindest versuchen - Der Compiler wird dann auch nur eine Warnmeldung ausgeben, den Code aber schlucken. Kernels Beispiel ist aber kein Beispiel, da public die Standard-Sichtbarkeit ist.mikescu hat geschrieben:AFAIK kann man die Sichtbarkeit in abgeleiteten Klassen nicht verringern. Da Destroy in TObject als public definiert ist, ist es in das auch in obigen Code. Wichtig ist override und der inherited Aufruf am Ende deines Destructor-Codes.Kernel hat geschrieben:btw: macht es in diesem Bezug wirklich einen Unterschied ob der Destructor public ist, oder nicht?
Also
Code: Alles auswählen
TMyObj = class(Tobject) destructor destroy;override; End;
Es ist auch möglich Constructor und Destructor als private zu deklarieren und damit keine Speicherlecks zu produzieren. Sie sind dann eben nur in der einen Unit sichtbar.
MfG Socke
Ein Gedicht braucht keinen Reim//Ich pack’ hier trotzdem einen rein
Ein Gedicht braucht keinen Reim//Ich pack’ hier trotzdem einen rein
-
carli
- Beiträge: 657
- Registriert: Sa 9. Jan 2010, 17:32
- OS, Lazarus, FPC: Linux 2.6.x, SVN-Lazarus, FPC 2.4.0-2
- CPU-Target: 64Bit
Re: Heaptrace
Die Sichtbarkeit des Destruktors hat nichts zu sagen.
Suche lieber dort, wo wirklich Speicher allokiert oder (nicht) freigegeben wird.
Suche lieber dort, wo wirklich Speicher allokiert oder (nicht) freigegeben wird.
-
Euklid
- Lazarusforum e. V.
- Beiträge: 2808
- Registriert: Fr 22. Sep 2006, 10:38
- OS, Lazarus, FPC: Lazarus v2.0.10, FPC 3.2.0
- Wohnort: Hessen
- Kontaktdaten:
Re: Heaptrace
mikescu hat recht, meist handelt es sich um Seiteneffekte (z.B. kann es sein, dass beim Auftreten eines Fehlers bestimmte Routinen nicht mehr so ausgeführt werden, wie es regulär sein sollte).Kernel hat geschrieben: Leider sind es hunderte Blöcke und nicht einzelner Einträge.
Tipp: Immer den ersten Fehler der heaptrc-Ausgabe beheben, dann erneut probieren.
Gruß, Euklid