Laut Joshua Blochs Effective Java (Second Edition) gibt es zwei finalize()
nützliche Szenarien :
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 umgehend aufgerufen wird, aber es ist möglicherweise besser, die Ressource zu spät als nie freizugeben, wenn der Client die explizite Beendigungsmethode nicht aufruft (hoffentlich selten). Der Finalizer sollte jedoch eine Warnung protokollieren, wenn er feststellt, dass die Ressource nicht beendet wurde
Eine zweite legitime Verwendung von Finalizern betrifft Objekte mit einheimischen Kollegen. 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 Java-Peer zurückgefordert wird. Ein Finalizer ist ein geeignetes Mittel, um diese Aufgabe auszuführen, vorausgesetzt, der native Peer verfügt über 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 alle erforderlichen Schritte ausführen, um die kritische Ressource freizugeben.
Weitere Informationen finden Sie unter Punkt 7, Seite 27.
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, während Ihr Objekt mit GCs versehen ist, werden Sie WidgetHandles verlieren.
Wichtig ist, dass die Fälle, in denen "Finalizer heißt nie", eher einfach aufgeschlüsselt werden:
In allen drei Fällen haben Sie entweder kein systemeigenes Leck (aufgrund der Tatsache, dass Ihr Programm nicht mehr ausgeführt wird) oder Sie haben bereits ein nicht systemeigenes Leck (wenn Sie verwaltete Objekte weiterhin zuweisen, ohne dass dies der Fall ist) GC'd).
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 während der Erstellung inkrementieren und in einem Finalizer dekrementieren - da keine Garantie dafür besteht, dass Ihre Objekte vorhanden sind abgeschlossen sein, wird dieser Dateizähler wahrscheinlich nie auf 0 zurückgehen. Dies ist wirklich ein Sonderfall des allgemeineren Prinzips, dass Sie nicht davon abhängen sollten, dass Ihr Programm normal beendet wird (Stromausfälle usw.).
Bei der Verwaltung nativer Ressourcen entsprechen die Fälle, in denen der Finalizer nicht ausgeführt wird, denen, die Sie nicht interessieren, wenn sie nicht ausgeführt werden.
quelle
close()
wird nie aufgerufen, bevor er nicht mehr erreichbar ist)Der Zweck dieser Methode wird in der API-Dokumentation wie folgt erläutert :
Wenn Sie sich außerdem für Gründe interessieren, aus denen Sprachentwickler entschieden haben, dass "Objekte unwiderruflich verworfen werden" ( gesammelter Müll ), die sich der Kontrolle des Anwendungsprogrammierers entziehen ("wir sollten uns niemals verlassen"), wurde dies in einer Antwort auf "related " erläutert frage :
Das obige Zitat stammt wiederum aus der offiziellen Dokumentation über Java-Entwurfsziele , dh es kann als maßgebliche Referenz angesehen werden, die erklärt, warum sich Java-Sprachdesigner für diesen Weg entschieden haben.
Eine ausführlichere und sprachunabhängigere Beschreibung dieser Einstellung finden Sie in OOSC, Abschnitt 9.6, Automatische Speicherverwaltung . Dieser Abschnitt beginnt mit einer eindeutigen Aussage:
quelle
Finalizer gibt es, weil von ihnen erwartet wurde, dass sie ein wirksames Mittel sind, um sicherzustellen, dass die Dinge aufgeräumt werden (auch wenn dies in der Praxis nicht der Fall ist), und weil sie bei ihrer Erfindung ein besseres Mittel sind, um die Aufräumarbeiten sicherzustellen (wie Phantomreferenzen und Versuchsanleitungen) -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 Bereinigungsmaßnahmen aufgewendet worden wäre, was jedoch während der anfänglichen Entwicklung von Java kaum klar war.
quelle
CAVEAT: Ich bin vielleicht nicht mehr auf dem neuesten Stand, aber so verstehe ich es seit ein paar Jahren:
Im Allgemeinen kann nicht garantiert werden, wann ein Finalizer ausgeführt wird - oder ob 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 Standard-Betriebsart).
Und es war bekannt, dass einige GCs das GC'ing von Objekten 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 genannter Abschaltmethoden gefördert.
Wenn Sie ein Objekt haben, das wirklich bereinigt werden muss, bevor es verworfen wird, und Sie den Benutzern nicht wirklich 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 der frühen Beispiele.
quelle
Der Google Java Style Guide enthält einige Ratschläge zu diesem Thema:
quelle
PhantomReference
und erstellenReferenceQueue
.PhantomReference
eine bessere Lösung. Finalizer sind eine Warze, die aus den Anfängen von Java übrig geblieben ist. GleicheObject.clone()
und rohe Typen gehören zu den am besten vergessenen Sprachen.In der Java-Sprachspezifikation (Java SE 7) heißt es:
quelle