Delphi-PRAXiS

Delphi-PRAXiS (https://www.delphipraxis.net/forum.php)
-   Programmieren allgemein (https://www.delphipraxis.net/40-programmieren-allgemein/)
-   -   Aufräumarbeiten bei Anwendungsende (https://www.delphipraxis.net/197721-aufraeumarbeiten-bei-anwendungsende.html)

Der schöne Günther 30. Aug 2018 12:23

Aufräumarbeiten bei Anwendungsende
 
Ein neues Feature in einer Delphi-Anwendung sorgt dafür dass die Anwendung zum Beenden mindestens fünf Sekunden benötigt, in seltenen Extremfällen auch mal gerne 30 Sekunden.


Die Anwendung räumt beim Ende akribisch auf. Speicher wird freigegeben, zum lesen geöffnete Dateien geschlossen, Netzwerkverbindungen zugemacht. Ja, ein paar Dinge sind beim Beenden unverzichtbar. Aber wirklich nur ein paar. Haben wir das falsch gemacht, war das unnötig?

Legende Raymond Chen meint Ja.
Zitat:

The building is being demolished. Don't bother sweeping the floor and emptying the trash cans and erasing the whiteboards. And don't line up at the exit to the building so everybody can move their in/out magnet to out. All you're doing is making the demolition team wait for you to finish these pointless housecleaning tasks.
Quelle

(Auch lesenswert)


Gibt es Meinungen aus der Delphi-Praxis hierzu? Wie macht ihr es? Ich spiele schon mit dem Gedanken die Anwendung umzubauen dass bei Ende nur das Allernötigste getan wird und sich dann selbst mit
Delphi-Quellcode:
ExitProcess(..)
abgeschossen wird...

Uwe Raabe 30. Aug 2018 12:40

AW: Aufräumarbeiten bei Anwendungsende
 
Ich denke, das ist eine Frage der persönlichen Einstellung. Beim Destroy einer Klasse weiß ich in der Regel nicht, ob lediglich die Instanz freigegeben wird oder das Programm beendet. Ebensowenig weiß ich, was um mich herum gerade passiert. Ich finde, jeder sollte den Platz so verlassen, wie er ihn vorgefunden hat. Womöglich verlässt sich ja auch jemand darauf, daß ich das tue. Ehrlich gesagt, wäre es mir auch zu viel Aufwand, jedesmal zu überprüfen ob ich jetzt aufräumen muss oder das auch entfallen kann. Daher bin ich hier auch auf der Seite der ordentlich Aufräumer und teile bewusst nicht die Ansicht von Raymond (was zugegeben nicht oft vorkommt, aber der programmiert vermutlich auch nicht in Delphi). Vielleicht schreibe ich auch einfach keine Programme, die merkbar lange zum Beenden brauchen.

Lemmy 30. Aug 2018 13:10

AW: Aufräumarbeiten bei Anwendungsende
 
Zitat:

Zitat von Der schöne Günther (Beitrag 1412010)
Gibt es Meinungen aus der Delphi-Praxis hierzu? Wie macht ihr es? Ich spiele schon mit dem Gedanken die Anwendung umzubauen dass bei Ende nur das Allernötigste getan wird und sich dann selbst mit
Delphi-Quellcode:
ExitProcess(..)
abgeschossen wird...

sehe ich keinen Vorteil drin. Der nächste Entwickler nach Dir räumt auf (schließt z.B. irgend welche Handles) und ist am Ende irritiert, dass sein Code nicht ausgeführt wird, weil ein Schlaumeier vor ihm irgendwo ein ExitProcess eingebaut hat.

Kleiner Tipp aus meinem Erfahrungsschatz (sprich ist mir schon mal passiert): Einfach mal einen Profiler (ProDelphi, AQ Time) laufen lassen und schauen WAS wirklich ZEit braucht, da kannst Du dann versuchen zu optimieren.

freimatz 30. Aug 2018 14:16

AW: Aufräumarbeiten bei Anwendungsende
 
In Ergänzung zu meinen Vorschreibern:
Zitat:

Zitat von Der schöne Günther (Beitrag 1412010)
Legende Raymond Chen meint Ja.

Nu ja, da geht es um DLLs. Außerdem: jeder hat mal einen schlechten Tag ;-)

Der schöne Günther 30. Aug 2018 14:24

AW: Aufräumarbeiten bei Anwendungsende
 
Danke für die Antworten bislang!

Zitat:

Zitat von Uwe Raabe (Beitrag 1412012)
Beim Destroy einer Klasse weiß ich in der Regel nicht, ob lediglich die Instanz freigegeben wird oder das Programm beendet. Ebensowenig weiß ich, was um mich herum gerade passiert.

Absolut, das kann man nicht wissen, das ein Destruktor in der Regel alles aufräumen sollte was man aufgebaut hast stellt sicher niemand in Frage ��


Zitat:

Zitat von freimatz (Beitrag 1412020)
Nu ja, da geht es um DLLs

In der Überschrift schon, aber das lässt sich auch übertragen. So zum Beispiel in dem anderen Artikel.

Zitat:

Zitat von Lemmy (Beitrag 1412014)
Der nächste Entwickler nach Dir räumt auf (schließt z.B. irgend welche Handles) und ist am Ende irritiert, dass sein Code nicht ausgeführt wird, weil ein Schlaumeier vor ihm irgendwo ein ExitProcess eingebaut hat.

Ja, aber wenn die Anwendung endet, dann endet sie halt. Sein Coe würde auch nicht ausgeführt bei Stromausfall oder wenn die Anwendung abstürzt. Das Betriebssystem kümmert sich nach Prozess-Ende schon selbst darum dass Dateien, Handles usw. ordentlich geschlossen werden.


In einer anderen Anwendung tun wir genau das: WENN Sie endet:
  1. Stelle Sicher dass alle kritischen Dinge (Ausgänge, Motoren, ...) im sicheren Zustand sind
  2. Schreibe Einstellungen auf die Platte
  3. Schreibe in Log-Datei dass die Anwendung nun zu Ende ist
  4. Andwendung endet

Dieser Teil muss natürlich gemacht werden und ist ganz spezifisch für die einzelne Anwendung. Ich fand das ziemlich sinnvoll.


Im konkreten Fall weiß ich auch was so lange braucht. Es wäre ein irrsinniger Aufwand das so umzubauen dass es sich jederzeit abbrechen ließe. Und es macht, wie der gute Raymond sagt, auch keine Sinn. Niemand interessiert sich mehr für das Ergebnis.

himitsu 30. Aug 2018 15:29

AW: Aufräumarbeiten bei Anwendungsende
 
Es gibt guten einen Grund, um immer aufzuräumen.

Wenn du am Ende noch einen Speicherlecktest ausführen willst.
Das geht ja nur, wenn auch vorher alles aufgeräumt wurde, denn nur dann siehst du auch, was davon wirklich die Lecks sind. (alles, was dann noch da ist, und was nicht "absichtlich" unfreigegeben blieb Delphi-Referenz durchsuchenSystem.RegisterExpectedMemoryLeak)

Zacherl 30. Aug 2018 15:37

AW: Aufräumarbeiten bei Anwendungsende
 
Halte es auch für guten Stil am Ende aufzuräumen. In der Regel passiert das doch eh "automatisch", wenn die letzte Klasse freigegeben wurde. Sollte es zumindest, wenn die Klassen selbst im Destructor für Ordnung sorgen.

Der schöne Günther 30. Aug 2018 17:05

AW: Aufräumarbeiten bei Anwendungsende
 
Vielleicht beeindruckt mich auch nur Raymond Chens anschauliches Beispiel so sehr. Ich meine, er hat ja nicht Unrecht. Welchen Sinn macht es, akribisch jedes Byte freizugeben wenn die Anwendung sowieso nicht mehr gebraucht wird?

Speicherleck-Tests sind ein guter Grund, aber das versuche ich mittlerweile eher über die Unit-Tests zu machen.


Dass die Anwendung am Schluss freundlich alle Verbindungen zumacht und Tschüss sagt, da hat der Benutzer auch nichts von (außer Wartezeit). Hmm…


Ich hätte erwartet mehr Zuspruch zu bekommen 🤔

Uwe Raabe 30. Aug 2018 17:16

AW: Aufräumarbeiten bei Anwendungsende
 
Zitat:

Zitat von Der schöne Günther (Beitrag 1412040)
Ich hätte erwartet mehr Zuspruch zu bekommen 🤔

Ich vermute mal, daß das Problem mit der Wartezeit vielleicht nicht so weit verbreitet ist.

Whookie 31. Aug 2018 09:37

AW: Aufräumarbeiten bei Anwendungsende
 
Ich kann mich dem nur Anschließen, mit übermäßiger Wartezeit beim Programmende hatte ich nur selten zu kämpfen. Mit Programmen die am Ende Daten leaken habe ich aber noch nie positive Erfahrungen gemacht (allein deshalb ist meiner Meinung nach, beim Programmende alles korrekt freizugeben).

Ob sich bei einem Stromausfall oder Crash das Betriebssystem nun wirklich um alles kümmert spielt daher für mich kaum eine Rolle und aus meiner Erfahrung würde ich sage: "Mal so mal so" 8-)

sh17 31. Aug 2018 12:57

AW: Aufräumarbeiten bei Anwendungsende
 
Vielleicht lässt sich der Speicherbereich, der hier anscheinend so viel Zeit in Anspruch nimmt, um bereinigt zu werden, anders organisieren??? Da müsste man nur wissen worum es geht?

Neutral General 31. Aug 2018 14:26

AW: Aufräumarbeiten bei Anwendungsende
 
Ist halt recht schwer einzuschätzen ohne genaueres zu wissen. Generell bin ich auch jemand der alles schön aufgeräumt haben will.
In der Praxis hat Raymond denke ich mal (evtl. Sonderfälle ggf. ausgeschlossen) Recht. Wenn der einzige Code der deine Anwendung noch ausführen wird bis zum endgültigen Ende das Freigeben von Speicher etc ist,
dann kann man sich diesen Code sparen. Ich hatte wie die meisten anderen hier auch noch nie das Problem, dass das Aufräumen so lange gebraucht hat, dass ich nicht-Aufräumen in Betracht ziehen musste.
Ich würde es wahrscheinlich mal probieren. Wenn der Geschwindigkeitsgewinn sehr groß wäre, dann würde ich es in Betracht ziehen.
Andererseits wäre für mich dann auch noch die Frage ob der Benutzer überhaupt (noch) etwas von der Anwendung sieht wenn diese aufräumt oder ob dann schon alle Formulare etc geschlossen sind.
Wenn das einzig sichtbare beim Aufräumen der Eintrag im Taskmanager ist, dann wird sich der User daran sicher nicht stören, denn für ihn ist das Programm aus, wenn er nichts mehr davon sieht.

Aber ist wahrscheinlich größtenteils ne Glaubensfrage, genauso wie ob man FreeAndNil bei lokalen Variablen benutzt oder nicht - Es nutzt rein gar nichts, aber für manche fühlt es sich sauberer an.

Zacherl 31. Aug 2018 15:12

AW: Aufräumarbeiten bei Anwendungsende
 
Tatsächlich hatte ich einmal eine Baumstruktur mit einigen tausend Nodes, für die alle eine Klasseninstanz im RAM residierte. Dieser Baum war recht kompliziert aufzuspannen und dementsprechend rechenintensiv war das Hinzufügen, aber auch Entfernen der Nodes (hatte kaskadierende Events mit Neuberechnungen zu Folge). Bei dieser Anwendung ist mir dann auch aufgefallen, dass das Aufräumen am Ende noch mehrere Sekunden angedauert hat. Beim Debuggen merkt man das ja recht schön, wenn zwischen dem Klick auf X und dem Umschalten auf Designtime Oberfläche in Delphi einige Zeit vergeht.

Habe mir dann auch so beholfen, dass die Klasse im
Delphi-Quellcode:
destructor
ein Flag setzt, was alle Neuberechnungen auf Eis gelegt hat und dann einfach sämtliche Nodes in einer Schleife freigibt und danach die Index-Liste löscht (
Delphi-Quellcode:
TList.Remove
bzw.
Delphi-Quellcode:
TList.IndexOf
wurde mir tatsächlich hier auch zum Flaschenhals, da die Nodes sich im Normalfall selbst (de-)registriert haben).
Das hat mir schon einen deutlichen Geschwindigkeitsboost gebracht. Hatte dann zeitweise noch überlegt
Delphi-Quellcode:
InitInstance
für meine Nodes zu überschreiben, damit ich einfach einen großen zusammenhängenden Speicherblock reservieren - und am Ende in einem Rutsch freigeben - kann. Die Idee habe ich allerdings wieder verworfen. Unter 64-Bit wäre das zwar kein Problem gewesen, da die Node-Klasse auch nicht sonderlich groß war, allerdings bestand sie aus einer Komposition mehrerer anderer Klassen, für die ich konsequenterweise das Spielchen dann auch hätte weitertreiben müssen.

Uwe Raabe 31. Aug 2018 16:10

AW: Aufräumarbeiten bei Anwendungsende
 
Zitat:

Zitat von Zacherl (Beitrag 1412133)
und dementsprechend rechenintensiv war das Hinzufügen, aber auch Entfernen der Nodes (hatte kaskadierende Events mit Neuberechnungen zu Folge).
...
Habe mir dann auch so beholfen, dass die Klasse im
Delphi-Quellcode:
destructor
ein Flag setzt, was alle Neuberechnungen auf Eis gelegt hat

In so einem Fall stelle ich mir dann immer die Frage, ob es nicht auch im laufenden Betrieb vorteilhaft wäre, die Neuberechnung nicht bei jeder Änderung durchzuführen, sondern z.B. mit einem NeedsRecalc-Flag oder einem BeginUpdate/Endupdate aufzuschieben. Dann braucht man bei Programmende nur ein BeginUpdate aufrufen und das zugehörige EndUpdate entfällt dann einfach (hier ist dann auch ein erklärender Kommentar angebracht, sonst materialisiert sich auf wundersame Weise dann in ein paar Monaten doch noch ein EndUpdate).

freimatz 3. Sep 2018 09:47

AW: Aufräumarbeiten bei Anwendungsende
 
Zitat:

Zitat von Der schöne Günther (Beitrag 1412022)
Zitat:

Zitat von Uwe Raabe (Beitrag 1412012)
Beim Destroy einer Klasse weiß ich in der Regel nicht, ob lediglich die Instanz freigegeben wird oder das Programm beendet. Ebensowenig weiß ich, was um mich herum gerade passiert.

Absolut, das kann man nicht wissen, das ein Destruktor in der Regel alles aufräumen sollte was man aufgebaut hast stellt sicher niemand in Frage ��

Nicht? Genau so habe ich Raymond aber verstanden.

Zitat:

Zitat von Der schöne Günther (Beitrag 1412040)
Vielleicht beeindruckt mich auch nur Raymond Chens anschauliches Beispiel so sehr. Ich meine, er hat ja nicht Unrecht. Welchen Sinn macht es, akribisch jedes Byte freizugeben wenn die Anwendung sowieso nicht mehr gebraucht wird?

Ja, es macht keinen Sinn alles freizugeben, wenn die Anwendung sowieso nicht mehr gebraucht wird. Aber: eben nur wenn. Wie Uwe schon schrieb, kann die Klassen das nicht (ohne weiteres) wissen ob das "wenn" nun eintritt.
Oder willst Du ein globales Flag Shutdown: Boolean einführen und in jedem destructor prüfen ob das gesetzt ist? :wink:

himitsu 3. Sep 2018 11:13

AW: Aufräumarbeiten bei Anwendungsende
 
Zitat:

Zitat von freimatz (Beitrag 1412308)
Oder willst Du ein globales Flag Shutdown: Boolean einführen und in jedem destructor prüfen ob das gesetzt ist? :wink:

Gibt es schon:
Delphi-Quellcode:
Application.Terminated
Aber so direkt in Komponenten sollte man es dann doch nicht verwenden, denn
* in einer Service-Anwendung kommt "Application" nicht aus der Unit Forms, sondern aus SvcMgr
* im FMX ist es FMX.Forms statt VCL.Forms
* In einem Thread wäre es
Delphi-Quellcode:
Self.Terminated
, falls der Thread in der RTL gekapselt wäre,
und außerhalb der Threadklasse könnte man auf die Idee kommen
Delphi-Quellcode:
TThread.CurrentThread.Terminated
zu nehmen, was aber nicht funktioniert, da CurrentThread eine "eigene" Klasseninstanz nutzt und der Terminated-Flag nicht durchgereicht wird.
* ...
und für eine Komponente/Unit ist beim Kompilieren aber nicht ersichtlich, wo sie verwendet wird.

Zacherl 3. Sep 2018 12:31

AW: Aufräumarbeiten bei Anwendungsende
 
Zitat:

Zitat von Uwe Raabe (Beitrag 1412136)
Zitat:

Zitat von Zacherl (Beitrag 1412133)
und dementsprechend rechenintensiv war das Hinzufügen, aber auch Entfernen der Nodes (hatte kaskadierende Events mit Neuberechnungen zu Folge).
...
Habe mir dann auch so beholfen, dass die Klasse im
Delphi-Quellcode:
destructor
ein Flag setzt, was alle Neuberechnungen auf Eis gelegt hat

In so einem Fall stelle ich mir dann immer die Frage, ob es nicht auch im laufenden Betrieb vorteilhaft wäre, die Neuberechnung nicht bei jeder Änderung durchzuführen, sondern z.B. mit einem NeedsRecalc-Flag oder einem BeginUpdate/Endupdate aufzuschieben. Dann braucht man bei Programmende nur ein BeginUpdate aufrufen und das zugehörige EndUpdate entfällt dann einfach (hier ist dann auch ein erklärender Kommentar angebracht, sonst materialisiert sich auf wundersame Weise dann in ein paar Monaten doch noch ein EndUpdate).

Genau so funktioniert es intern im Grunde auch :thumb: Da wie du schon vermutest auch praktisch jede Änderung an Properties eine Neu-berechnung zur Folge hat, war eine
Delphi-Quellcode:
BeginUpdate
/
Delphi-Quellcode:
EndUpdate
Funktionalität sowieso zwingend notwendig.

CCRDude 3. Sep 2018 13:27

AW: Aufräumarbeiten bei Anwendungsende
 
Zitat:

Zitat von Neutral General (Beitrag 1412125)
Wenn das einzig sichtbare beim Aufräumen der Eintrag im Taskmanager ist, dann wird sich der User daran sicher nicht stören, denn für ihn ist das Programm aus, wenn er nichts mehr davon sieht.

Es sei denn, er fährt seinen Rechner runter, während das Programm noch offen ist. Dann bemerkt Windows, das das Programm auf die Beenden-Message nicht im vorgegebenen Zeitraum reagiert, und informiert den Benutzer darüber.

Im Rahmen der ganzen Telemtrie-Dinger dürfte MS dann auch merken, dass das Programm häufiger "nicht ordnungsgemäß" funktioniert. Wer weiß, wo das irgendwann schaden kann? Gibt ja zum Beispiel bei Windows Upgrades immer mal wieder Programme, die wegen "Inkompatibilität" mehr oder weniger still entfernt werden. Das Risiko, mit so einem nicht regelkonformen Verhalten irgendwann auf dem falschen Index zu landen, wäre mir zu groß.


Alle Zeitangaben in WEZ +1. Es ist jetzt 17:24 Uhr.

Powered by vBulletin® Copyright ©2000 - 2025, Jelsoft Enterprises Ltd.
LinkBacks Enabled by vBSEO © 2011, Crawlability, Inc.
Delphi-PRAXiS (c) 2002 - 2023 by Daniel R. Wolf, 2024-2025 by Thomas Breitkreuz