Problem mit Heap-Trace

Für Fragen rund um die Ide und zum Debugger
Benutzeravatar
photor
Beiträge: 443
Registriert: Mo 24. Jan 2011, 21:38
OS, Lazarus, FPC: Arch Linux: L 2.2.6 FPC 3.2.2 (Gtk2)
CPU-Target: 64Bit

Problem mit Heap-Trace

Beitrag von photor »

Hallo Forum,

ich habe ein Programm, dass mittlerweile ordentlich durch läuft und weitgehend das macht, was es soll. :wink:

Nun wollte ich mit Heap Trace auf die Suche nach Speicherlecks gehen und habe also in den Projekt-Einstellungen unter den Debugger-Optionen einfach "Heaptrc-Unit verwenden (-gh)" angehakt.

Das Ergebnis ist, jetzt erhalte ich eine Exception und lande im Assembler-Fenster (was leider nicht wirklich hilft. Der Code, bei dem das passiert ist der hier:

Code: Alles auswählen

begin
  ResultFilename := PD.BMSCResultsPath + 'RFC-' + IntToStr(PD.NBins_RFC) + '_' +
    Bolt_Name + '.txt';

  AssignFile(RFC_Output_file,ResultFileName);

  // in case of 1st DLC a new file is created; all other results are appended
  if (IDLC=0) then
    Rewrite(RFC_Output_file)
  else
    Append(RFC_Output_file);

  FATEntry := TFAtEntry.Create;
  FATEntry := FatigueList[IDLC];
  .......

das ist aus einer Routine, die bei jedem Durchlauf das Ergebnis an ein Ergebnisfile anhängen soll - beim ersten Durchlauf (IDLC = 0) soll das File neu angelegt werden. Das passiert auch. Aber wenn -gh gesetzt ist, wird die Exception (wohl beim Append) geworfen - das Resultfile enthält die erste Lösung, die folgende dann nicht mehr.

Was passiert da? Was mache ich falsch? Wie bekomme ich bessere Ergebnisse (meine Erinnerung sagt mir, dass Heap-Trace mir eigentlich sagt, welcher Speicher nicht frei gegeben wird und das nach Ende des Programms). Gibt es eine bessere Art und Weise, Speicherlecks zu erkennen?

Ein bisschen ratlos,
Photor

Benutzeravatar
Winni
Beiträge: 1577
Registriert: Mo 2. Mär 2009, 16:45
OS, Lazarus, FPC: Laz2.2.2, fpc 3.2.2
CPU-Target: 64Bit
Wohnort: Fast Dänemark

Re: Problem mit Heap-Trace

Beitrag von Winni »

Hi!

Ich bin genauso ratlos wie Du, aber vielleicht folgender Trick:

Beim Start des Pogramms die Datei anlegen (FormCreate) mit null Byte.
Danach musst Du Dich nicht mehr kümmern, ob die Datei existiert und kannst alles mit append regeln.

Winni

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

Re: Problem mit Heap-Trace

Beitrag von theo »

Kannst du das Problem auf das Minimum eindampfen und als Projekt anhängen?
So fällt mir dazu nichts ein.

Benutzeravatar
Winni
Beiträge: 1577
Registriert: Mo 2. Mär 2009, 16:45
OS, Lazarus, FPC: Laz2.2.2, fpc 3.2.2
CPU-Target: 64Bit
Wohnort: Fast Dänemark

Re: Problem mit Heap-Trace

Beitrag von Winni »

Hi!

Ich schreibe den HeapTrace Output in eine Datei.

Die lpr-Datei wie folgt anpassen (Linux):

Code: Alles auswählen

const trc= '/tmp/Heap.trc';

begin
  
  if UseHeapTrace then
  begin
    if FileExists(trc) then DeleteFile(trc);
    SetHeapTraceOutput(trc);
  end;
  // Standard:
  RequireDerivedFormResource:=True;
  Application.Initialize;             
....

end.

Winni

wp_xyz
Beiträge: 4869
Registriert: Fr 8. Apr 2011, 09:01

Re: Problem mit Heap-Trace

Beitrag von wp_xyz »

photor hat geschrieben:
So 20. Feb 2022, 11:40
Aber wenn -gh gesetzt ist, wird die Exception (wohl beim Append) geworfen
Wieso "wohl beim Append"? Bist du denn nicht mit dem Debugger durch deinen Code gesteppt? Der zeigt dir doch genau die Zeile, in der es kracht.

PascalDragon
Beiträge: 825
Registriert: Mi 3. Jun 2020, 07:18
OS, Lazarus, FPC: L 2.0.8, FPC Trunk, OS Win/Linux
CPU-Target: Aarch64 bis Z80 ;)
Wohnort: München

Re: Problem mit Heap-Trace

Beitrag von PascalDragon »

photor hat geschrieben:
So 20. Feb 2022, 11:40
Das Ergebnis ist, jetzt erhalte ich eine Exception und lande im Assembler-Fenster (was leider nicht wirklich hilft. Der Code, bei dem das passiert ist der hier:

Code: Alles auswählen

begin
  ResultFilename := PD.BMSCResultsPath + 'RFC-' + IntToStr(PD.NBins_RFC) + '_' +
    Bolt_Name + '.txt';

  AssignFile(RFC_Output_file,ResultFileName);

  // in case of 1st DLC a new file is created; all other results are appended
  if (IDLC=0) then
    Rewrite(RFC_Output_file)
  else
    Append(RFC_Output_file);

  FATEntry := TFAtEntry.Create;
  FATEntry := FatigueList[IDLC];
  .......

das ist aus einer Routine, die bei jedem Durchlauf das Ergebnis an ein Ergebnisfile anhängen soll - beim ersten Durchlauf (IDLC = 0) soll das File neu angelegt werden. Das passiert auch. Aber wenn -gh gesetzt ist, wird die Exception (wohl beim Append) geworfen - das Resultfile enthält die erste Lösung, die folgende dann nicht mehr.
Schließt du die Datei auch wieder?
FPC Compiler Entwickler

Benutzeravatar
photor
Beiträge: 443
Registriert: Mo 24. Jan 2011, 21:38
OS, Lazarus, FPC: Arch Linux: L 2.2.6 FPC 3.2.2 (Gtk2)
CPU-Target: 64Bit

Re: Problem mit Heap-Trace

Beitrag von photor »

PascalDragon hat geschrieben:
So 20. Feb 2022, 14:21
[...]
Schließt du die Datei auch wieder?
Jup. Habe aber zur Sicherheit gerade nochmal nach gesehen (Ist nicht alles mein Code, daher).

Ciao,
Photor

Benutzeravatar
photor
Beiträge: 443
Registriert: Mo 24. Jan 2011, 21:38
OS, Lazarus, FPC: Arch Linux: L 2.2.6 FPC 3.2.2 (Gtk2)
CPU-Target: 64Bit

Re: Problem mit Heap-Trace

Beitrag von photor »

wp_xyz hat geschrieben:
So 20. Feb 2022, 13:11
photor hat geschrieben:
So 20. Feb 2022, 11:40
Aber wenn -gh gesetzt ist, wird die Exception (wohl beim Append) geworfen
Wieso "wohl beim Append"? Bist du denn nicht mit dem Debugger durch deinen Code gesteppt? Der zeigt dir doch genau die Zeile, in der es kracht.
Genau deshalb ja "wohl". Ich steppe durch und beim Append lande ich aber im Assembler. Aus dem Assembler werde ich aber nicht ganz schlau und sehe nicht genau, was der Auslöser war.

Ich überlege ja die ganze Zeit, ob es eine bessere (modernere) Methode gibt, die Ergebnisse an die Datei(en) anzuhängen (das können schnell über hundert Files werden; und Anhänge-Durchläufe auch in der selben Größenordnung und mehr). Also die Files als TStringList in Speicher halten wird zu Speicher-intensiv sein.

Verrückt ist ja, dass es im Normallauf funktioniert hat und nach Einschalten des Heap-Trace stolpert. Wenn ich das Wiki richtig verstehe, muss aber nichts weiter gemacht werden (Debugging allgemein war ja bereits aktiviert).

Ciao,
Photor

Benutzeravatar
af0815
Lazarusforum e. V.
Beiträge: 6198
Registriert: So 7. Jan 2007, 10:20
OS, Lazarus, FPC: FPC fixes Lazarus fixes per fpcupdeluxe (win,linux,raspi)
CPU-Target: 32Bit (64Bit)
Wohnort: Burgenland
Kontaktdaten:

Re: Problem mit Heap-Trace

Beitrag von af0815 »

Ich mache generell vor den Dateioperationen eine Abfrage mit FileExists um festzustellen ob es die Datei gibt und vor allen ob ich das auch erwarte.

Weiters sichere ich alle Dateioperationen mit try..except ab und zusätzlich mit try..finally wenn es um das schliessen und freigeben des Filehandle geht.

Beim Tracen würde ich den Fehler in den except Block durchfallen lassen (mit F9 einfach weiter) und in dem Block mir die Fehlermeldung holen.
Blöd kann man ruhig sein, nur zu Helfen muss man sich wissen (oder nachsehen in LazInfos/LazSnippets).

wp_xyz
Beiträge: 4869
Registriert: Fr 8. Apr 2011, 09:01

Re: Problem mit Heap-Trace

Beitrag von wp_xyz »

photor hat geschrieben:
So 20. Feb 2022, 16:37
Ich überlege ja die ganze Zeit, ob es eine bessere (modernere) Methode gibt, die Ergebnisse an die Datei(en) anzuhängen (das können schnell über hundert Files werden; und Anhänge-Durchläufe auch in der selben Größenordnung und mehr). Also die Files als TStringList in Speicher halten wird zu Speicher-intensiv sein.
Moderner wäre die Anwendung eines TFileStream. Ob das für deine Zwecke auch "besser" ist, vermag ich nicht zu beurteilen.

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

Re: Problem mit Heap-Trace

Beitrag von theo »

Tja, mich hätte ja schon interessiert, warum der mit Heaptrc abschmiert, aber ohne den Code von photor...
photor hat geschrieben:
So 20. Feb 2022, 16:37
Ich überlege ja die ganze Zeit, ob es eine bessere (modernere) Methode gibt, die Ergebnisse an die Datei(en) anzuhängen (das können schnell über hundert Files werden; und Anhänge-Durchläufe auch in der selben Größenordnung und mehr). Also die Files als TStringList in Speicher halten wird zu Speicher-intensiv sein.
Ich hab dir hier mal ein Bsp. mit TFileStream gemacht.

Code: Alles auswählen

procedure TForm1.Button1Click(Sender: TObject);
var
  FS: TFileStream;
  FN: string;
begin
  FN := 'strmtest.txt';
  FS := TFileStream.Create(FN, fmCreate);
  try
    FS.WriteAnsiString('test');
  finally
    FS.Free;
  end;

  FS := TFileStream.Create(FN, fmOpenWrite);
  try
    FS.Seek(0, soFromEnd);
    FS.WriteAnsiString('noch ein test');
    FS.WriteDWord(123456);
  finally
    FS.Free;
  end;

  FS := TFileStream.Create(FN, fmOpenRead);
  try
    Caption := FS.ReadAnsiString + FS.ReadAnsiString + IntToStr(FS.ReadDWord);
  finally
    FS.Free;
  end;
end;       

Benutzeravatar
photor
Beiträge: 443
Registriert: Mo 24. Jan 2011, 21:38
OS, Lazarus, FPC: Arch Linux: L 2.2.6 FPC 3.2.2 (Gtk2)
CPU-Target: 64Bit

Re: Problem mit Heap-Trace

Beitrag von photor »

theo hat geschrieben:
Mo 21. Feb 2022, 15:39
Tja, mich hätte ja schon interessiert, warum der mit Heaptrc abschmiert, aber ohne den Code von photor...
Tja, der Code ist leider nicht frei. Und runter reduziert bekomme ich den jetzt so schnell auch nicht. Finde das auch doof, so am virtuellen rumdoktorn.

Ausgangspunkt war ja, dass ich nicht genau wusste, ob ich noch irgendwo was vergessen hatte, zu aktivieren (laut Wiki: nein).
theo hat geschrieben:
Mo 21. Feb 2022, 15:39
photor hat geschrieben:
So 20. Feb 2022, 16:37
Ich überlege ja die ganze Zeit, ob es eine bessere (modernere) Methode gibt, die Ergebnisse an die Datei(en) anzuhängen (das können schnell über hundert Files werden; und Anhänge-Durchläufe auch in der selben Größenordnung und mehr). Also die Files als TStringList in Speicher halten wird zu Speicher-intensiv sein.
Ich hab dir hier mal ein Bsp. mit TFileStream gemacht.

Code: Alles auswählen

procedure TForm1.Button1Click(Sender: TObject);
var
  FS: TFileStream;
  FN: string;
begin
  FN := 'strmtest.txt';
  FS := TFileStream.Create(FN, fmCreate);
  try
    FS.WriteAnsiString('test');
  finally
    FS.Free;
  end;

  FS := TFileStream.Create(FN, fmOpenWrite);
  try
    FS.Seek(0, soFromEnd);
    FS.WriteAnsiString('noch ein test');
    FS.WriteDWord(123456);
  finally
    FS.Free;
  end;

  FS := TFileStream.Create(FN, fmOpenRead);
  try
    Caption := FS.ReadAnsiString + FS.ReadAnsiString + IntToStr(FS.ReadDWord);
  finally
    FS.Free;
  end;
end;       
Auf TFileStream war ich auch gestoßen. Ich werde mir das mal ansehen (Danke für den Start-Code). Ob das wirklich besser ist, muss ich probieren. TStringList fällt leider wegen der möglichen Masse an Daten aus.

Ciao,
Photor

Benutzeravatar
af0815
Lazarusforum e. V.
Beiträge: 6198
Registriert: So 7. Jan 2007, 10:20
OS, Lazarus, FPC: FPC fixes Lazarus fixes per fpcupdeluxe (win,linux,raspi)
CPU-Target: 32Bit (64Bit)
Wohnort: Burgenland
Kontaktdaten:

Re: Problem mit Heap-Trace

Beitrag von af0815 »

Code: Alles auswählen

begin
  ResultFilename := PD.BMSCResultsPath + 'RFC-' + IntToStr(PD.NBins_RFC) + '_' +
    Bolt_Name + '.txt';

    try
       AssignFile(RFC_Output_file,ResultFileName);

       // in case of 1st DLC a new file is created; all other results are appended
       if (IDLC=0) then
         Rewrite(RFC_Output_file)
       else
         Append(RFC_Output_file);
  except
     on E : Exception do Debugln('Exception->' + E.Message );
   end;

  FATEntry := TFAtEntry.Create;
  FATEntry := FatigueList[IDLC];
  .......
Statt debugln kann man writeln oder was anders nehmen, hauptsache kann kommt an den Exceptionstext.

Das mit dem Debugger und den Codefenster kenne ich, besonders dann wenn die Exception das Programm stört, wenn dieses gerade in einem anderen Thread ist. Normalerweise sage ich dann F9 und warte auf die Meldung in der Exception. Könnte hier auch was bringen und wenn, so kosten die paar Zeilen mal nicht viel.
Blöd kann man ruhig sein, nur zu Helfen muss man sich wissen (oder nachsehen in LazInfos/LazSnippets).

Benutzeravatar
photor
Beiträge: 443
Registriert: Mo 24. Jan 2011, 21:38
OS, Lazarus, FPC: Arch Linux: L 2.2.6 FPC 3.2.2 (Gtk2)
CPU-Target: 64Bit

Re: Problem mit Heap-Trace

Beitrag von photor »

theo hat geschrieben:
Mo 21. Feb 2022, 15:39
Ich hab dir hier mal ein Bsp. mit TFileStream gemacht.

Code: Alles auswählen

procedure TForm1.Button1Click(Sender: TObject);
var
  FS: TFileStream;
  FN: string;
begin
  FN := 'strmtest.txt';
  FS := TFileStream.Create(FN, fmCreate);
  try
    FS.WriteAnsiString('test');
  finally
    FS.Free;
  end;

  FS := TFileStream.Create(FN, fmOpenWrite);
  try
    FS.Seek(0, soFromEnd);
    FS.WriteAnsiString('noch ein test');
    FS.WriteDWord(123456);
  finally
    FS.Free;
  end;

  FS := TFileStream.Create(FN, fmOpenRead);
  try
    Caption := FS.ReadAnsiString + FS.ReadAnsiString + IntToStr(FS.ReadDWord);
  finally
    FS.Free;
  end;
end;       
Hm. Hab sowas mal eingebaut. Aber dann erhalte ich keine reine ASCII-Datei mehr; sie enthält wohl noch die Länge des geschriebenen Strings (binär als Integer). Das sprengt mir leider das Fileformat der Ergebnisfiles (von Kollegen für ihre Tools genutzt). Ich probiere aber weiter.

Ciao,
Photor

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

Re: Problem mit Heap-Trace

Beitrag von theo »

photor hat geschrieben:
Mo 21. Feb 2022, 20:59
Hm. Hab sowas mal eingebaut. Aber dann erhalte ich keine reine ASCII-Datei mehr; sie enthält wohl noch die Länge des geschriebenen Strings (binär als Integer).
Ja, das ist der Trick bei WriteAnsiString, aber du kannst auch nur Write nehmen wie im Bsp. unten, dann kommt keine Länge mit.

https://wiki.freepascal.org/TFileStream

Antworten