Sollte ich nach jedem Object.Create einen try-finally-Block setzen?

7

Ich habe eine allgemeine Frage zu Best Practice in OO Delphi. Gegenwärtig stelle ich try-finally-Blöcke überall dort hin, wo ich ein Objekt erzeuge, um dieses Objekt nach der Benutzung freizugeben (um Speicherlecks zu vermeiden). Zum Beispiel:

%Vor%

anstelle von:

%Vor%

Glauben Sie, dass es eine gute Übung oder zu viel Aufwand ist? Und was ist mit der Leistung?

    
markus_ja 27.05.2010, 16:35
quelle

8 Antworten

15

Meiner Meinung nach gibt es nur einen Grund, warum eine Objektkonstruktion nicht gefolgt werden sollte ( oder" in "wie Mason wies ) a try / finally block.

  1. Wenn die Lebensdauer eines Objekts von einem anderen Objekt verwaltet wird.

Diese Verwaltung kann drei Formen annehmen:

  1. Die Referenz eines Objekts hat einen Bereich außerhalb des lokalen Blocks und wird an anderer Stelle freigegeben - wie ein Feldelement, das im Destruktor freigegeben wurde.
  2. Ein Objekt, das sofort zu einer Liste hinzugefügt wird, die später das Objekt freigibt.
  3. Ein Objekt mit einem zugeordneten Lifetime Manager, z. B. wie Sie den Eigentümer an ein VCL-Steuerelement übergeben.

Mit # 1 , wenn die Referenz einen größeren Bereich hat sollte die Referenz sofort auf Null gesetzt werden, wenn sie nicht sofort erstellt wird. Auf diese Weise, wenn es als Referenz überprüft wird, wissen Sie, dass Sie eine genaue Lesung haben. Dies ist am häufigsten bei Elementobjekten der Fall, die als Teil einer größeren Klasse erstellt und dann bereinigt werden, wenn das übergeordnete Objekt zerstört wird.

Mit # 2 , wenn ein Objekt zu einer Liste hinzugefügt wird möchten Sie nur einen try-except -Block (eines der wenigen, die ich benutze) verwenden falls eine Ausnahme auftritt, nachdem das Objekt erstellt wurde und bevor es der Verwaltungsliste hinzugefügt wird. Idealerweise fügt die erste Zeile nach der Konstruktion sie der Liste hinzu, oder die Liste ist eigentlich eine Factory-Klasse, die Ihnen ein Objekt gibt, das bereits zur Liste hinzugefügt wurde.

Mit # 3 , wenn ein Objekt einen anderen Lifetime Manager hat , sollten Sie wirklich sicherstellen, dass die Verwaltung durch diesen Manager das Richtige ist. Wenn Sie ein VCL-Steuerelement erstellen, könnten Sie versucht sein, das Formular (oder ein anderes Steuerelement) zu besitzen, was jedoch zusätzlichen Aufwand für die Konstruktion und die Zerstörung bedeutet. Wenn möglich, sollten Sie es explizit freigeben, das gilt insbesondere, wenn Sie das Steuerelement einmal aktivieren, dann wissen Sie, dass Sie es im Destruktor Ihres Formulars freigeben oder wenn es geschlossen wird. Dies ist nur möglich, wenn die Erstellung der Steuerung dynamischer ist.

Also, es ist eine bewährte Methode, viele try / finally Blöcke zu verwenden. Sie sollten nur ein paar try / except -Blöcke haben, und die meisten von ihnen sollten sehr spezifische Ausnahme-Typen abfangen und / oder die Ausnahme erneut auslösen. Wenn Sie mehr try / except als try / finally Blöcke haben, dann machen Sie es falsch .

    
Jim McKeeth 27.05.2010, 20:48
quelle
17

Es ist definitiv die beste Vorgehensweise, try-finally zu verwenden.

Wenn eine Ausnahme ausgelöst wird, wird das Objekt freigegeben .

Was die Leistung angeht: messen , bevor Sie optimieren.

    
Frank Shearar 27.05.2010 16:40
quelle
13

Wie Frank sagte: "Was die Leistung angeht: messen Sie, bevor Sie optimieren." Wiederholen Sie es, um zu betonen.

Wenn Sie eine Gruppe von Objekten in einer Methode erstellen, müssen Sie auch keinen try..finally-Block für jede von ihnen verwenden. Das kann zu einem hässlichen Eindruck führen. create, try, create, try, create, try, do something, finally, free, finally, free, finally, free. Ugh! Stattdessen können Sie die Objektreferenzen am Anfang der Methode auf nil setzen, dann alle erstellen, einen try-Block ausführen und sie alle im finally-Abschnitt freigeben.

Das spart Overhead und Leistung (obwohl Sie den Unterschied wahrscheinlich nie bemerken werden), aber was noch wichtiger ist, macht Ihren Code sauberer und einfacher zu lesen, während das Sicherheitsniveau beibehalten wird.

    
Mason Wheeler 27.05.2010 16:50
quelle
5

Um Teil zwei Ihrer Frage zu beantworten:
try finally hat kaum einen Overhead.

Tatsächlich gibt es viele Methoden, die einen impliziten Versuch haben ... endlich zu blockieren. Zum Beispiel mit einer Funktion, die eine lokale Variable eines beliebigen Schnittstellentyps verwendet und einem Wert einen Wert zuweist.

- Jeroen

    
Jeroen Wiert Pluimers 27.05.2010 17:07
quelle
5

Letztes Jahr bei Delphi Developer Days habe ich Marco Cantus privaten Code-Vorrat gesehen und er versucht es jedes Mal, wenn er etwas kreiert.

Jemand hat ihn danach gefragt, und er sagte, er versuche es die ganze Zeit.

Aber es ist besonders eine gute Idee für Multi-Threaded-Code, wenn es darum geht, kritische Abschnitte zu betreten und zu verlassen, obwohl das nicht zum Thema ist, ist es eine gute Sache, sich daran zu erinnern.

Offensichtlich ist es manchmal ein bisschen aufdringlich und wenn es nicht in der Kultur Ihres Arbeitsumfelds ist, in Ihrer Robsutness genau zu sein, kann es Sie dazu bringen, wie ein Goodie-Two-Shoes auszusehen. Aber ich denke, es ist eine gute Idee. Es ist so ähnlich wie Delphis Versuch, manuelle Garbage Collection zu erzwingen.

    
Peter Turner 27.05.2010 17:33
quelle
2

Wenn Sie das Objekt im Konstruktor einer Klasse erstellen und das Objekt der einschließenden Klasse gehört, möchten Sie es im Destruktor der besitzenden Klasse freilassen.

Ich neige dazu, FreeAndNil () anstelle von Free zu verwenden.

EDIT: Aber wie andere schon gesagt haben, willst du definitiv immer das, was du erstellst, befreien.

    
TrueWill 27.05.2010 17:26
quelle
1

Ja, es ist immer eine gute Idee (wichtig), wenn der Code, der das Objekt erstellt, dafür verantwortlich ist, es freizugeben. Wenn nicht, dann probiere / endlich ist es nicht angebracht, aber dann ist es auch wieder nicht .Frei auf jeden Fall!

Es kann jedoch mühsam sein, wenn dieser Standardcode Ihre "Geschäftslogik" hervorhebt, und Sie sollten vielleicht einen Ansatz in Betracht ziehen, der die gleiche Garantie hat, Ihre Objekte zu befreien, der aber viel sauberer ist (und andere Vorteile hat), wie meine eigene AutoFree () Implementierung .

Mit AutoFree () könnte dann Ihr Code geschrieben werden:

%Vor%

oder alternativ, da die Implementierung einen Verweis auf eine Referenz verwendet (um Auto-NIL'ing sowie Free'ing zu aktivieren), können Sie sogar Ihre Referenzen vorregistrieren, für die Sie eine AutoFree-Funktion wünschen Housekeeping-Deklarationen weg von Ihrer Geschäftslogik und halten Sie das echte "Fleisch" Ihres Codes so sauber wie möglich (dies ist besonders vorteilhaft, wenn potenziell mehrere Objekte frei sein müssen):

%Vor%

Nicht in meinem ursprünglichen Beitrag gezeigt ist eine spätere Ergänzung zu dem Mechanismus zur Unterstützung der Registrierung mehrerer Referenzen in einem einzigen AutoFree () -Aufruf, aber ich bin mir sicher, dass Sie die Änderungen herausfinden können, um dies selbst zu unterstützen, wenn Sie möchte dies tun können:

%Vor%     
Deltics 27.05.2010 21:26
quelle
-4

Auch wenn es viel zu empfehlen ist, dies zu tun, werde ich es nicht immer tun.

Meine Regeln zur Verwendung oder Nichtbenutzung des try / finally:

  • Die Chance für das Objekt, abzustürzen und zu brennen.
  • Wie oft das Objekt erstellt wurde. Wenn ich weiß, dass Ihr Objekt selten erstellt wird (nicht mehr als 5-6 Mal in der Anwendungslebensdauer), kann ich mit einem 20KB Speicherleck leben - für den Fall, dass es "stirbt", ohne befreit zu werden.
  • Anzahl der ausgelaufenen Speicher für den Fall, dass das Objekt abstürzt.
  • Komplexität des Codes. Try / except macht den Code wirklich hässlich. Wenn es eine 5-Zeilen-Prozedur gibt, verwende ich immer try / except.
  • Anwendungsdateispanne. Wenn Ihre Anwendung für Tage ausgeführt werden muss, dann möchte ich JEDES Stück Speicher freigeben, sonst sammelt sich das Leck an.

Der einzige Ort, an dem es schwierig ist, eine Entscheidung zu treffen, ist, wenn Sie beim Erstellen des Objekts Tausende von Malen Leistung benötigen (z. B. in einer Schleife). In diesem Fall verwende ich try nicht, es sei denn, das Objekt führt einfache Aufgaben aus und es besteht eine geringe Chance, dass es abstürzt.

    
Sahara 27.05.2010 20:33
quelle

Tags und Links