it-swarm.com.de

Warum ist die Finalize-Methode in Java enthalten?

Laut dieser Beitrag sollten wir uns niemals auf die aufzurufende Finalisierungsmethode verlassen. Warum hat Java es überhaupt in die Programmiersprache aufgenommen?

Es scheint eine schreckliche Entscheidung zu sein, in jede Programmiersprache eine Funktion aufzunehmen, die aufgerufen werden könnte .

44
patstuart

Laut Joshua Blochs Effective Java (Second Edition)) gibt es zwei Szenarien, in denen finalize() nützlich ist:

  1. Eine Möglichkeit besteht darin, als „Sicherheitsnetz“ zu fungieren, falls der Eigentümer eines Objekts vergisst, seine explizite Beendigungsmethode aufzurufen. Es gibt zwar keine Garantie dafür, dass der Finalizer sofort aufgerufen wird, es ist jedoch möglicherweise besser, die Ressource spät als nie freizugeben, in den (hoffentlich seltenen) Fällen, in denen der Client die explizite Beendigungsmethode nicht aufruft. Der Finalizer sollte jedoch eine Warnung protokollieren, wenn er feststellt, dass die Ressource nicht beendet wurde

  2. Eine zweite legitime Verwendung von Finalisierern betrifft Objekte mit nativen Peers. Ein nativer Peer ist ein natives Objekt, an das ein normales Objekt über native Methoden delegiert. Da ein nativer Peer kein normales Objekt ist, weiß der Garbage Collector nichts davon und kann es nicht zurückfordern, wenn sein Peer Java Peer) zurückgefordert wird. Ein Finalizer ist ein geeignetes Mittel, um dies durchzuführen Aufgabe, vorausgesetzt, der native Peer enthält keine kritischen Ressourcen. Wenn der native Peer Ressourcen enthält, die sofort beendet werden müssen, sollte die Klasse über eine explizite Beendigungsmethode verfügen, wie oben beschrieben. Die Beendigungsmethode sollte alles tun, was zum Freigeben der kritischen Ressource erforderlich ist.

Weitere Informationen finden Sie unter Punkt 7, Seite 27.

41
bbalchev

Finalizer sind wichtig für die Verwaltung nativer Ressourcen. Beispielsweise muss Ihr Objekt möglicherweise ein WidgetHandle vom Betriebssystem mithilfe einer Nicht-Java-API zuweisen. Wenn Sie dieses WidgetHandle nicht freigeben, wenn Ihr Objekt GC-fähig ist, treten WidgetHandles aus.

Wichtig ist, dass die Fälle "Finalizer wird nie genannt" ziemlich einfach aufgeschlüsselt werden:

  1. Das Programm wird schnell heruntergefahren
  2. Das Objekt "lebt für immer" während der Laufzeit des Programms
  3. Der Computer wird ausgeschaltet/Ihr Prozess wird vom Betriebssystem/etc. Abgebrochen

In allen drei Fällen haben Sie entweder kein natives Leck (aufgrund der Tatsache, dass Ihr Programm nicht mehr ausgeführt wird) oder Sie haben bereits ein nicht natives Leck (wenn Sie weiterhin verwaltete Objekte zuweisen, ohne dass diese GC-fähig sind).

Bei der Warnung "Verlassen Sie sich nicht darauf, dass der Finalizer aufgerufen wird" geht es wirklich darum, Finalizer nicht für die Programmlogik zu verwenden. Sie möchten beispielsweise nicht verfolgen, wie viele Ihrer Objekte in allen Instanzen Ihres Programms vorhanden sind, indem Sie einen Zähler in einer Datei irgendwo während der Erstellung inkrementieren und in einem Finalizer dekrementieren - da es keine Garantie dafür gibt, dass Ihre Objekte dies tun Wenn dies abgeschlossen ist, wird dieser Dateizähler wahrscheinlich nie wieder auf 0 zurückgesetzt. Dies ist wirklich ein Sonderfall des allgemeineren Prinzips, dass Sie nicht davon abhängen sollten, dass Ihr Programm normal beendet wird (Stromausfälle usw.).

Für die Verwaltung nativer Ressourcen entsprechen die Fälle, in denen der Finalizer nicht ausgeführt wird, Fällen, in denen es Ihnen egal ist, ob er nicht ausgeführt wird.

55
Ryan Cavanaugh

Der Zweck dieser Methode wird in API-Dokumentation wie folgt erläutert:

es wird aufgerufen, wenn die virtuelle Maschine Java festgestellt hat, dass kein Thread mehr auf dieses Objekt zugreifen kann, der noch nicht gestorben ist, außer aufgrund einer Aktion von die Finalisierung eines anderen Objekts oder einer anderen Klasse, die/die finalisiert werden kann ...

der übliche Zweck von finalize... besteht darin, Bereinigungsaktionen auszuführen, bevor das Objekt unwiderruflich verworfen wird . Beispielsweise kann die Finalisierungsmethode für ein Objekt, das eine Eingabe/Ausgabe-Verbindung darstellt, explizite E/A-Transaktionen ausführen, um die Verbindung zu trennen, bevor das Objekt dauerhaft verworfen wird ...


Wenn Sie zusätzlich an Gründen interessiert sind, warum Sprachdesigner gewählt haben, dass "Objekt unwiderruflich verworfen wird" (Müll gesammelt), liegt dies außerhalb der Kontrolle des Anwendungsprogrammierers ("). wir sollten uns niemals verlassen "), dies wurde erklärt in eine Antwort auf verwandte Fragen :

automatische Speicherbereinigung ... beseitigt ganze Klassen von Programmierfehlern, die C- und C++ - Programmierer stören. Sie können Java Code mit der Gewissheit entwickeln, dass das System schnell viele Fehler findet und dass große Probleme erst nach dem Versand Ihres Produktionscodes inaktiv werden.

Das obige Zitat stammt wiederum aus offizielle Dokumentation über Java Designziele , dh es kann als maßgebliche Referenz angesehen werden, die erklärt, warum Java Sprachdesigner dies entschieden haben Weg.

Eine detailliertere und sprachunabhängigere Diskussion dieser Einstellung finden Sie in OOSC Abschnitt 9.6 Automatische Speicherverwaltung (eigentlich nicht nur Dieser Abschnitt, aber das gesamte Kapitel 9 ist sehr lesenswert, wenn Sie sich für solche Dinge interessieren. Dieser Abschnitt beginnt mit einer eindeutigen Aussage:

Eine gute O-O-Umgebung sollte einen automatischen Speicherverwaltungsmechanismus bieten, der nicht erreichbare Objekte erkennt und zurückfordert, sodass sich Anwendungsentwickler auf ihre Aufgabe konzentrieren können - die Anwendungsentwicklung.

Die vorangegangene Diskussion sollte ausreichen, um zu zeigen, wie wichtig es ist, eine solche Einrichtung zur Verfügung zu haben. Mit den Worten von Michael Schweitzer und Lambert Strether:

Ein objektorientiertes Programm ohne automatische Speicherverwaltung entspricht in etwa einem Schnellkochtopf ohne Sicherheitsventil: Früher oder später wird das Ding sicher explodieren !

5
gnat

Finalizer existieren, weil von ihnen erwartet wurde, dass sie ein wirksames Mittel sind, um sicherzustellen, dass die Dinge bereinigt werden (obwohl dies in der Praxis nicht der Fall ist), und weil sie bei ihrer Erfindung ein besseres Mittel sind, um die Bereinigung sicherzustellen (wie Phantomreferenzen und das Ausprobieren) -ressourcen) gab es noch nicht. Im Nachhinein wäre Java wahrscheinlich besser, wenn der Aufwand für die Implementierung der "Finalize" -Funktion für andere Bereinigungsmittel aufgewendet worden wäre, aber das war während der Zeit kaum klar Java wurde ursprünglich entwickelt.

4
supercat

CAVEAT: Ich bin vielleicht veraltet, aber das ist mein Verständnis von vor ein paar Jahren:

Im Allgemeinen gibt es keine Garantie dafür, wann ein Finalizer ausgeführt wird - oder sogar, dass er überhaupt ausgeführt wird. Bei einigen JVMs können Sie jedoch eine vollständige GC und Finalisierung anfordern, bevor das Programm beendet wird (was natürlich bedeutet, dass das Programm länger dauert zu beenden, und das ist nicht die Standardbetriebsart).

Es war bekannt, dass einige GCs GC-Objekte mit Finalisierern explizit verzögern oder vermeiden, in der Hoffnung, dass dies zu einer besseren Leistung bei Benchmarks führen würde.

Diese Verhaltensweisen stehen leider im Widerspruch zu den ursprünglichen Gründen, aus denen Finalizer empfohlen wurden, und haben stattdessen die Verwendung explizit als Shutdown-Methoden empfohlen.

Wenn Sie ein Objekt haben, das wirklich bereinigt werden muss, bevor es verworfen wird, und wenn Sie den Benutzern wirklich nicht vertrauen können, ist ein Finalizer möglicherweise noch eine Überlegung wert. Aber im Allgemeinen gibt es gute Gründe, warum Sie sie im modernen Java -Code) nicht so oft sehen wie in einigen frühen Beispielen.

3
keshlam

Das Google Java Style Guide hat einige weise Ratschläge zu diesem Thema:

Es ist äußerst selten , Object.finalize Zu überschreiben.

Tipp : Tu es nicht. Wenn Sie unbedingt müssen, lesen und verstehen Sie zuerst Effective Java Punkt 7, "Vermeiden Sie Finalizer", sehr sorgfältig und dann don tu es nicht.

1
Daniel Pryden

Die Java-Sprachspezifikation (Java SE 7) besagt:

Finalizer bieten die Möglichkeit, Ressourcen freizugeben, die von einem automatischen Speichermanager nicht automatisch freigegeben werden können. In solchen Situationen würde die einfache Rückgewinnung des von einem Objekt verwendeten Speichers nicht garantieren, dass die darin enthaltenen Ressourcen zurückgewonnen werden.

1
Benni