Heaptrace

Für alles, was in den übrigen Lazarusthemen keinen Platz, aber mit Lazarus zutun hat.
Kernel
Beiträge: 35
Registriert: Di 13. Okt 2009, 14:10

Heaptrace

Beitrag von Kernel »

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

Benutzeravatar
theo
Beiträge: 11104
Registriert: Mo 11. Sep 2006, 19:01

Re: Heaptrace

Beitrag von theo »

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

Beitrag von carli »

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

Kernel
Beiträge: 35
Registriert: Di 13. Okt 2009, 14:10

Re: Heaptrace

Beitrag von Kernel »

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:

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
  $083B840D
Das o.g. ist die Zuweisung eines Events!
Was soll ich denn da wieder freigeben?

Ist das normal?

Gruß
Kernel

Benutzeravatar
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

Beitrag von corpsman »

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.
--
Just try it

Kernel
Beiträge: 35
Registriert: Di 13. Okt 2009, 14:10

Re: Heaptrace

Beitrag von Kernel »

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.
Nein, so einfach ist es nicht ;-)

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

Beitrag von carli »

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)

Benutzeravatar
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

Beitrag von m.fuchs »

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...
Das kommt schon aus deinem Code. Mach mal ein neues Testprojekt mit einem leerem Formular. Im OnCreate dieses Form machst du mal folgendes:

Code: Alles auswählen

procedure TForm1.FormCreate(Sender: TObject);
var
  x: TObject;
begin
  x := TObject.Create;
end;
Sonst nix.

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]
Und so weiter (korrigiert mich bitte, wenn ich hier Unsinn erzähle).

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

Kernel
Beiträge: 35
Registriert: Di 13. Okt 2009, 14:10

Re: Heaptrace

Beitrag von Kernel »

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

Benutzeravatar
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

Beitrag von m.fuchs »

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...
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.
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;
Mit einem FreeAndNil(x); sind die Probleme auch alle weg. Schau also mal nach den Fehlern die auf deine Codezeilen verweisen und berichtige diese entsprechend. Ich behaupte, dadurch werden sich auch die (alle) anderen Probleme in Wohlgefallen auflösen.

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

Kernel
Beiträge: 35
Registriert: Di 13. Okt 2009, 14:10

Re: Heaptrace

Beitrag von Kernel »

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

Code: Alles auswählen

TMyObj = class(Tobject)
  destructor destroy;override;
End;
oder

Code: Alles auswählen

TMyObj = class(Tobject)
public
  destructor destroy;override;
End;

Benutzeravatar
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

Beitrag von m.fuchs »

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;
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.
0118999881999119725-3

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

Beitrag von Socke »

mikescu hat geschrieben:
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;
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.
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.
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

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

Beitrag von carli »

Die Sichtbarkeit des Destruktors hat nichts zu sagen.
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

Beitrag von Euklid »

Kernel hat geschrieben: Leider sind es hunderte Blöcke und nicht einzelner Einträge.
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).

Tipp: Immer den ersten Fehler der heaptrc-Ausgabe beheben, dann erneut probieren.

Gruß, Euklid

Antworten