Delphi-PRAXiS
Seite 3 von 4     123 4      

Delphi-PRAXiS (https://www.delphipraxis.net/forum.php)
-   Object-Pascal / Delphi-Language (https://www.delphipraxis.net/32-object-pascal-delphi-language/)
-   -   Delphi TObjectList.Free erzeugt AV (https://www.delphipraxis.net/183819-tobjectlist-free-erzeugt-av.html)

jaenicke 7. Feb 2015 12:41

AW: TObjectList.Free erzeugt AV
 
Das Aufräumen sollte immer dort passieren, wo das Objekt auch erstellt wurde. Wenn du eine TStringList im Konstruktor eines Objekts erstellst, sollte diese auch im Destruktor freigegeben werden. Sprich das Objekt, zu dem die Liste gehört, ist auch dafür verantwortlich. Natürlich musst das Objekt, das die Liste enthält, z.B. das Formular, auch freigegeben werden, damit das funktioniert. Und so geht es weiter bis zur obersten Ebene, bei der es kein übergeordnetes Objekt mehr gibt.

Aber das ist eine der wichtigsten Prinzipien der objektorientierten Programmierung. Dass du dich nicht in Verantwortlichkeiten anderer Objekte einmischst und so Kreuzbeziehungen usw. erzeugst.

Wenn du eine einzige Liste führst, in das du diverse Objekte wirfst /werfen musst, nur damit diese freigegeben werden, ist das keine gute Struktur.

SvB 7. Feb 2015 12:46

AW: TObjectList.Free erzeugt AV
 
Musste den Code gerade noch mal etwas anpassen:
Delphi-Quellcode:
TShowModalCenter = class helper for TForm
  function ShowModalCenter(ACenterForm: TForm): Integer;
end;

function TShowModalCenter.ShowModalCenter(ACenterForm: TForm): Integer;
var
  X, Y: Integer;
begin
  X := ((ACenterForm.Width - Width) div 2) + ACenterForm.Left;
  Y := ((ACenterForm.Height - Height) div 2) + ACenterForm.Top;
  if X < Screen.DesktopLeft then
    X := Screen.DesktopLeft;
  if Y < Screen.DesktopTop then
    Y := Screen.DesktopTop;
  SetBounds(X, Y, Width, Height);
  Result := ShowModal;
end;

Sir Rufo 7. Feb 2015 12:57

AW: TObjectList.Free erzeugt AV
 
So eine ich beuge mal vor allem irgendwie vor Funktion ist absoluter Overkill und führt nur zu einem unsauberen Programmierstil. Wird ja immer alles so schön aufgeräumt am Schluss.

Gut im normalen Betrieb dauert es ca. 1h bis der Speicher überläuft, aber wir haben keinen MemLeak - dann ist doch alles gut, oder etwa nicht?

Ein super Anti-Beispiel ist die FireMonkey ListBox aus XE7. Füll da mal so 10.000 Elemente rein (ist nur damit man auch was sieht) und dann gemütlich durch die Liste scrollen - rauf und runter. Toll, geht, aber was sagt der TaskManager zum Thema Speicherbedarf: Der wächst und wächst und wächst ... mit jedem Scrollen und hört einfach nicht auf. Es gibt aber keinen MemLeak, denn alles wird am Ende ja brav aufgeräumt. Dort jetzt den Fehler zu finden ist aufwändig. Bei einem MemLeak schaue ich mir die Instanzen an, wo es die meisten Leaks gibt und verfolge, wer die erzeugt und schwupps bin ich an der fehlerhaften Stelle.

So habe ich die MemLeaks in dem RestResponseDatasetAdapter gefunden und ausgemerzt.

Diese Art und Weise der Programmierung ist ähnlich schlimm, wie das paranoide Exception fangen. Lasst euch doch die Exceptions (so früh wie möglich) und die Leaks um die Ohren fliegen, dann wisst ihr wenigstens, wo es noch etwas zu tun gibt (sozusagen als automatischer ToDo-Eintrag).

Falls es nicht bekannt sein sollte: Wenn sich die Anwendung beendet wird auch der gesamte Speicher der Anwendung freigegeben, ob Leak oder nicht, es bleibt nichts zurück.

SvB 7. Feb 2015 13:27

AW: TObjectList.Free erzeugt AV
 
@Sir Rufo:
Du hast schon recht, verstehe ich. Das steht auch noch das ein oder andere auf meiner ToDo Liste. Ich hab nur gerade das Problem, dass ich mit meinem Projekt etwas hinten dran bin und der Kunde schon jammert, dass er jetzt mal was sehen will. Auch wenns im Moment für den ein oder anderen QuickAndDirty ist, ich muss mal was fertig bekommen. Übrigens: dem Kunden ist es egal wie es programmiert ist, der will klicki bunti was schönes haben.

Die andere Sache ist die, dass Du beim Testen niemals alles ausmerzen kannst. Man klickt halt anders rum, wie das ein Anwender tut. Hab ja schon MadExcept im Projekt und den Anwendern gesagt, die sollen mir den erzeugten Bericht senden, wenn eine Meldung kommt. Das machen aber vielleicht nur 30%, die anderen klicken immer weg und jammern hinterher, das Programm wäre ja Mist oder so ähnlich.

Mit den Exception-Berichten hangele ich mich dann schon Stück für Stück an das Problem. try except nutze ich so gut wie gar nicht, ich bin schon bemüht ordentlich zu coden. Es soll Rund laufen, der Anwender soll zufrieden sein, dann ist auch der GF vom Kunden zufrieden. So ist der Plan.

Auch wenn ich jetzt vielleicht wieder geschlagen werden: Ich nutze manchmal das System, was hier beschrieben wird und dieser Beitrag basiert auf diesem Interface mit OjectList.
Ich finde das in manchen Fällen ganz Nett und hilfreich, verkürzt den Code, man kanns auch oft besser lesen, weils nicht so viel verschachtelt ist. Hilfmittel finde ich immer gut, sonst würde ich ja in Assembler programmieren.

Meine ToDo Liste hat noch einige Punkte, aber eins nach dem anderen. Einer davon ist, dass ich die Exception Berichte im Hintergrund automatisch gesendet bekomme, dass ich dann handeln kann.

jaenicke 8. Feb 2015 18:11

AW: TObjectList.Free erzeugt AV
 
Zitat:

Zitat von Sir Rufo (Beitrag 1289128)
Falls es nicht bekannt sein sollte: Wenn sich die Anwendung beendet wird auch der gesamte Speicher der Anwendung freigegeben, ob Leak oder nicht, es bleibt nichts zurück.

Das stimmt so nicht. Wenn Systemressourcen reserviert wurden, werden zwar die meisten auch automatisch aufgeräumt, aber nicht alle. In einem solchen Fall war es dann so, dass das Programm zwar problemlos ein paarmal lief, aber nach dem etwa 30. Durchlauf das Betriebssystem (in dem Fall XP) insgesamt nicht mehr richtig reagierte...
Mit Vista und Windows 7 hat sich da zwar einiges getan, aber ganz aus der Welt ist das Problem AFAIK dennoch nicht.

Sir Rufo 8. Feb 2015 18:59

AW: TObjectList.Free erzeugt AV
 
Zitat:

Zitat von jaenicke (Beitrag 1289228)
Zitat:

Zitat von Sir Rufo (Beitrag 1289128)
Falls es nicht bekannt sein sollte: Wenn sich die Anwendung beendet wird auch der gesamte Speicher der Anwendung freigegeben, ob Leak oder nicht, es bleibt nichts zurück.

Das stimmt so nicht. Wenn Systemressourcen reserviert wurden, werden zwar die meisten auch automatisch aufgeräumt, aber nicht alle. In einem solchen Fall war es dann so, dass das Programm zwar problemlos ein paarmal lief, aber nach dem etwa 30. Durchlauf das Betriebssystem (in dem Fall XP) insgesamt nicht mehr richtig reagierte...
Mit Vista und Windows 7 hat sich da zwar einiges getan, aber ganz aus der Welt ist das Problem AFAIK dennoch nicht.

Full ack, ich hatte auch noch überlegt, ob ich das noch mit anspreche, habe mich aber dagegen entschieden. Manchmal muss man reduzieren, sonst sieht man den Wald vor lauter Bäumen nicht. Solche Ressourcen sollte man über ein selbstzerstörendes Interface reservieren :)

himitsu 8. Feb 2015 20:51

AW: TObjectList.Free erzeugt AV
 
Und selbst wenn Vieles inzwischen automatisch freigegeben wird.

Früher gab es in Windows nur einen großen Arbeitsspeicher, in dem alle Programme rumschrieben.
Die Nachteile kennen wir:
  • Ein Speicherleck im Programm blieb für immer bestehen, auch nach Ende des Programms.
  • Ein Buffer-Overflow konnte nicht nur eigenen Speicher zerstören, sondern auch den von anderen Programmen oder gar vom Windows selber.
  • ...

Und nun hat man nur durch Aufräumen die Möglichkeit, später auch achzusehn, ob man irgendwo was vergessen hat
und kann somit eventuell später Programmteile problemloser wiederverwenden.

Das Resultat sieht man am Delphi, denn im Commandline-Compiler war es nicht schlimm, aber im Inline-Compiler sah man die Auswirkungen der Speicherlecks, denn auch nach dem Compilieren verstopfte es die IDE immer mehr.


Und nur weil man jetzt denkt, daß etwas sowieso bis zum Programmende benötigt wird und man denkt "ach egal, Windows räumt schon auf", wer weiß was in Zukunft mal ist.
Wenn schon, dann sollte man immer ordentlich arbeiten. (PS: siehe Signatur)

Sir Rufo 8. Feb 2015 21:24

AW: TObjectList.Free erzeugt AV
 
Momentchen a mal,

ich schreibe meine Programme immer mit
Delphi-Quellcode:
ReportMemoryLeaksOnShutdown := true;
. Dann weiß ich, dass ich vergessen habe, irgendwo etwas korrekt freizugeben.

Wenn ich jetzt aber irgendeine sonstwas Sammelliste im Programm habe, die alle Instanzen aufnimmt und dann am Ende garantiert freigibt, dann habe ich beim Beenden keine MemLeaks. Toll, ich bin ein Held!

Oder doch nur der größte Tor von allen?

Plötzlich melden sich auf einmal die Benutzer, weil nach 2-5h Betrieb der Anwendung ein Speicherfehler kommt: "Arbeitsspeicher voll!"

Und warum? Denken, verstehen, handeln. Dann auf meine Signatur schauen und nicken.

Und nochmal, ich verwende keine solchen Garbage-Collector-Listen (denn das sind die) (@himitsu schau mal in deine Signatur), sondern gebe den Speicher kontrolliert frei. Und falls ich es vergessen habe, dann knallt mit der FastMM das beim Beenden um die Ohren und das ist gut so. Wenn das nicht mehr kommt und ich am Arbeitsspeicherverbrauch nicht die Uhrzeit ablesen kann, erst dann habe ich es richtig gemacht.

SvB 9. Feb 2015 06:51

AW: TObjectList.Free erzeugt AV
 
Gibt es eine Möglichkeit in seinem eigenen Programm mitprotokollieren zu lassen, durch was Speicher verbraucht wird? Am besten wäre die Unit und das einzelne Objekt, die protokolliert wird.

Angenommen ich hab jetzt nicht sauber gearbeitet und während der Laufzeit wird der Speicherverbrauch immer höher, am Ende wirds aber abgeräumt und ich bekomme durch ReportMemoryLeaksOnShutdown := true; keine Meldung.

Wie kann ich diesen Speicherverbrauch ermittelt, damit ich die Objekte entsprechend kontrolliert wieder freigeben kann? (Manchmal sieht man es ja nicht mehr, auch wenn man 100 mal über den Code schaut)
Ich werde ja auch niemals das Programm 2 bis 5 Stunden am Stück testen und damit so arbeiten, wie es ein Benutzer macht. Trotzdem möchte ich sowas gerne herausfinden.

Stevie 9. Feb 2015 07:05

AW: TObjectList.Free erzeugt AV
 
Zitat:

Zitat von SvB (Beitrag 1289247)
Gibt es eine Möglichkeit in seinem eigenen Programm mitprotokollieren zu lassen, durch was Speicher verbraucht wird?

Müsste gehen, indem du
Delphi-Quellcode:
CheckBlocksOnShutdown
aus der FastMM4.pas von außen zugänglich machst.

Alternativ kannst du aber auch AQTime nutzen, das hat nen Memory Profiler.


Alle Zeitangaben in WEZ +1. Es ist jetzt 19:26 Uhr.
Seite 3 von 4     123 4      

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