Ich muss wissen, wann die finalize()
Methode in der aufgerufen wird JVM
. Ich habe eine Testklasse erstellt, die beim Aufrufen der finalize()
Methode in eine Datei schreibt, indem sie überschrieben wird. Es wird nicht ausgeführt. Kann mir jemand den Grund sagen, warum es nicht ausgeführt wird?
330
finalize()
und die Speicherbereinigung hat keine Auswirkungen.Antworten:
Im Allgemeinen ist es am besten, sich nicht auf
finalize()
Aufräumarbeiten usw. zu verlassen .Laut Javadoc (was es wert wäre, gelesen zu werden) ist es:
Wie Joachim betonte, kann dies im Leben eines Programms niemals passieren, wenn das Objekt immer zugänglich ist.
Außerdem kann nicht garantiert werden, dass der Garbage Collector zu einem bestimmten Zeitpunkt ausgeführt wird. Im Allgemeinen versuche ich zu sagen, dass dies
finalize()
wahrscheinlich nicht die beste Methode im Allgemeinen ist, es sei denn, Sie benötigen etwas Bestimmtes.quelle
finalize
wäre dies nützlich?finalize()
Methode on für die Hauptklasse wird aufgerufen, wenn eine >> Instanz << der Klasse durch Speicherbereinigung erfasst wird, nicht, wenn die Hauptmethode beendet wird. Und außerdem die Hauptklasse kann Müll , bevor die Anwendung beendet gesammelt werden; zB in einer Multithread-App, in der der "Haupt" -Thread andere Threads erstellt und dann zurückkehrt. (In der Praxis wäre ein nicht standardmäßiger Klassenlader erforderlich ....)Die
finalize
Methode wird aufgerufen, wenn ein Objekt Müll sammeln soll. Dies kann jederzeit geschehen, nachdem es für die Speicherbereinigung in Frage kommt.Beachten Sie, dass es durchaus möglich ist, dass ein Objekt niemals Müll sammelt (und daher
finalize
niemals aufgerufen wird). Dies kann passieren, wenn das Objekt niemals für gc berechtigt ist (da es über die gesamte Lebensdauer der JVM erreichbar ist) oder wenn zwischen dem Zeitpunkt, zu dem das Objekt berechtigt wird, und dem Zeitpunkt, zu dem die JVM nicht mehr ausgeführt wird, tatsächlich keine Speicherbereinigung ausgeführt wird (dies geschieht häufig mit simple Testprogramme).Es gibt Möglichkeiten, die JVM anzuweisen,
finalize
auf Objekten ausgeführt zu werden, die noch nicht aufgerufen wurden, aber ihre Verwendung ist auch keine gute Idee (die Garantien dieser Methode sind auch nicht sehr stark).Wenn Sie sich
finalize
für den korrekten Betrieb Ihrer Anwendung verlassen, machen Sie etwas falsch.finalize
sollte nur zur Bereinigung von (normalerweise nicht Java) Ressourcen verwendet werden. Und das genau deshalb , weil die JVM nicht garantiert, dassfinalize
jemals ein Objekt aufgerufen wird.quelle
Closable
Schnittstelle (und die Idee dahinter) wahrscheinlich.close()
genau das, was Sie möchten: Schließen / Verwerfen Sie die Ressource und fordern Sie den Benutzer Ihrer Klasse auf, sie zum richtigen Zeitpunkt aufzurufen. Sie könnten einen hinzufügen möchtenfinalize
Methode „nur speichern zu sein“, aber das wäre eher ein Debugging - Tool als eine tatsächliche Fix (weil es nicht zuverlässig genug ist).System.gc()
, um FileInputStream :: finalize () aufzurufen, dann konnte ich die Datei verschieben.zitiert aus: http://www.janeg.ca/scjp/gc/finalize.html
Sie können diesen Artikel auch überprüfen:
quelle
Die Java-
finalize()
Methode ist kein Destruktor und sollte nicht zur Verarbeitung der Logik verwendet werden, von der Ihre Anwendung abhängt. Die Java-Spezifikation besagt, dass es keine Garantie dafür gibt, dass diefinalize
Methode während der Lebensdauer der Anwendung überhaupt aufgerufen wird.Was Sie wahrscheinlich wollen, ist eine Kombination aus
finally
und eine Bereinigungsmethode, wie in:quelle
Schauen Sie sich Effective Java, 2. Ausgabe, Seite 27 an. Punkt 7: Vermeiden Sie Finalizer
Verwenden Sie stattdessen try-finally, um eine Ressource zu beenden:
quelle
Die Finalize-Methode wird aufgerufen, nachdem der GC festgestellt hat, dass das Objekt nicht mehr erreichbar ist, und bevor der vom Objekt verwendete Speicher tatsächlich zurückgefordert wird.
Wenn ein Objekt niemals unerreichbar wird,
finalize()
wird es niemals aufgerufen.Wenn der GC nicht ausgeführt wird, wird er
finalize()
möglicherweise nie aufgerufen. (Normalerweise wird der GC nur ausgeführt, wenn die JVM entscheidet, dass wahrscheinlich genug Müll vorhanden ist, damit es sich lohnt.)Es kann mehr als einen GC-Zyklus dauern, bis der GC feststellt, dass ein bestimmtes Objekt nicht erreichbar ist. (Java-GCs sind normalerweise "Generationskollektoren" ...)
Sobald der GC feststellt, dass ein Objekt nicht erreichbar und finalisierbar ist, wird es in eine Finalisierungswarteschlange gestellt. Die Finalisierung erfolgt normalerweise asynchron mit dem normalen GC.
(Die JVM-Spezifikation erlaubt einer JVM tatsächlich , niemals Finalizer auszuführen ... vorausgesetzt, sie beansprucht nicht den von den Objekten verwendeten Speicherplatz zurück. Eine auf diese Weise implementierte JVM wäre verkrüppelt / nutzlos, aber dieses Verhalten ist "erlaubt". .)
Das Ergebnis ist, dass es unklug ist, sich auf die Finalisierung zu verlassen, um Dinge zu tun, die in einem bestimmten Zeitrahmen erledigt werden müssen. Es ist "Best Practice", sie überhaupt nicht zu verwenden. Es sollte einen besseren (dh zuverlässigeren) Weg geben, um das zu tun, was Sie mit der
finalize()
Methode versuchen .Die einzige legitime Verwendung für die Finalisierung besteht darin, Ressourcen zu bereinigen, die mit Objekten verknüpft sind, die durch Anwendungscode verloren gegangen sind. Selbst dann sollten Sie versuchen, den Anwendungscode so zu schreiben, dass die Objekte überhaupt nicht verloren gehen. (Verwenden Sie beispielsweise Java 7+ Try-with-Resources, um sicherzustellen, dass dies
close()
immer aufgerufen wird ...)Es ist schwer zu sagen, aber es gibt einige Möglichkeiten:
quelle
Da es eine Unsicherheit beim Aufrufen der Methode finalize () durch JVM gibt (nicht sicher, ob finalized (), die überschrieben wird, ausgeführt wird oder nicht), ist es für Studienzwecke besser zu beobachten, was passiert, wenn finalize () aufgerufen wird Erzwingen Sie, dass die JVM die Garbage Collection per Befehl aufruft
System.gc()
.Insbesondere wird finalize () aufgerufen, wenn ein Objekt nicht mehr verwendet wird. Aber wenn wir versuchen, es durch Erstellen neuer Objekte aufzurufen, gibt es keine Gewissheit über seinen Aufruf. Aus Sicherheitsgründen erstellen wir ein
null
Objekt,c
das offensichtlich keine zukünftige Verwendung hat. Daher sehen wir denc
Finalize-Aufruf des Objekts .Beispiel
Ausgabe
Hinweis - Auch nach dem Drucken von bis zu 70 und danach, wenn das Objekt b nicht im Programm verwendet wird, besteht die Unsicherheit, dass b von JVM gelöscht wird oder nicht, da "Aufgerufene Finalisierungsmethode in Klasse Bike ..." nicht gedruckt wird.
quelle
System.gc();
ist keine Garantie dafür, dass die Garbage Collection tatsächlich ausgeführt wird.finalize druckt die Anzahl für die Klassenerstellung aus.
Main
Wie du siehst. Die folgende Ausgabe zeigt, dass der GC zum ersten Mal ausgeführt wurde, wenn die Klassenanzahl 36 beträgt.
quelle
Nachdem ich in letzter Zeit mit Finalizer-Methoden gerungen habe (um Verbindungspools während des Testens zu entsorgen), muss ich sagen, dass dem Finalizer viele Dinge fehlen. Unter Verwendung von VisualVM zum Beobachten sowie unter Verwendung schwacher Referenzen zum Verfolgen der tatsächlichen Interaktion stellte ich fest, dass die folgenden Dinge in einer Java 8-Umgebung (Oracle JDK, Ubuntu 15) zutreffen:
Letzter Gedanke
Die Finalisierungsmethode ist unzuverlässig, kann jedoch nur für eine Sache verwendet werden. Sie können sicherstellen, dass ein Objekt vor der Müllabfuhr geschlossen oder entsorgt wurde, um eine Ausfallsicherung zu implementieren, wenn Objekte mit einem komplexeren Lebenszyklus, der eine Aktion am Lebensende beinhaltet, korrekt behandelt werden. Das ist der einzige Grund, warum ich mir vorstellen kann, dass es sich lohnt, es zu überschreiben.
quelle
Ein Objekt kann für die Garbage Collection oder GC verwendet werden, wenn es nicht über Live-Threads oder statische Aktualisierungen erreichbar ist. Mit anderen Worten, Sie können sagen, dass ein Objekt für die Garbage Collection berechtigt ist, wenn alle Verweise null sind. Zyklische Abhängigkeiten werden nicht als Referenz gezählt. Wenn also Objekt A eine Referenz von Objekt B und Objekt B eine Referenz von Objekt A hat und keine andere Live-Referenz hat, können sowohl Objekt A als auch B für die Garbage Collection verwendet werden. Im Allgemeinen kann ein Objekt in folgenden Fällen in Java zur Speicherbereinigung verwendet werden:
quelle
final
Feld eines Objekts während einer langsamen Berechnung wiederholt verwendet wird und das Objekt danach nie mehr verwendet wird, wird das Objekt bis zum letzten Mal am Leben gehalten, wenn der Quellcode das Feld anfordert, oder könnte die JIT das Feld in ein Objekt kopieren temporäre Variable und dann das Objekt vor der Berechnung verlassen?GC.KeepAlive()
Funktion, die nichts anderes tut, als den GC zu zwingen, anzunehmen, dass er möglicherweise ein Objekt verwendet, aber ich kenne keine solche Funktion in Java. Man könnte einevolatile
Variable für diesen Zweck verwenden, aber die Verwendung einer Variablen nur für einen solchen Zweck erscheint verschwenderisch.FinalizerReference
, sodass kein GC-Zyklus erforderlich ist, um herauszufinden, dass keine vorhanden sind Verweise. Die Synchronisation ist ausreichend , um ein , um sicherzustellen , geschieht-vor - Beziehung; Da die Finalisierung möglicherweise (tatsächlich) in einem anderen Thread ausgeführt wird, ist sie häufig ohnehin formal erforderlich. Java 9 wird hinzufügenReference.reachabilityFence
...Finalize
aufgerufen, wenn die JIT Code erzeugt, der dies direkt tut . Würde Synchronisationscode normalerweise für Objekte erwartet, die nur in einem einzelnen Thread verwendet werden sollen? Wenn ein Objekt eine Aktion ausführt, die rückgängig gemacht werden muss, bevor es abgebrochen wird (z. B. das Öffnen einer Socket-Verbindung und die ausschließliche Verwendung der Ressource am anderen Ende), wäre es eine Katastrophe, wenn ein Finalizer die Verbindung schließt, während der Code noch den Socket verwendet . Wäre es normal, dass Code die Synchronisation verwendet ...Die Finalisierungsmethode kann nicht garantiert werden. Diese Methode wird aufgerufen, wenn das Objekt für die GC in Frage kommt. Es gibt viele Situationen, in denen die Objekte möglicherweise nicht durch Müll gesammelt werden.
quelle
Manchmal, wenn es zerstört wird, muss ein Objekt eine Aktion ausführen. Wenn ein Objekt beispielsweise über eine Nicht-Java-Ressource wie ein Dateihandle oder eine Schriftart verfügt, können Sie überprüfen, ob diese Ressourcen freigegeben sind, bevor Sie ein Objekt zerstören. Um solche Situationen zu verwalten, bietet Java einen Mechanismus namens "Finalisieren". Durch Abschluss können Sie bestimmte Aktionen definieren, die auftreten, wenn ein Objekt aus dem Garbage Collector entfernt werden soll. Um einer Klasse einen Finalizer hinzuzufügen, definieren Sie einfach die Methode finalize () . Die Java-Ausführungszeit ruft diese Methode immer dann auf, wenn ein Objekt dieser Klasse gelöscht werden soll. Innerhalb der Finalisierungsmethode ()Sie geben Aktionen an, die ausgeführt werden sollen, bevor ein Objekt zerstört wird. Der Garbage Collector wird regelmäßig nach Objekten durchsucht, die sich nicht mehr auf einen laufenden Status oder indirekt auf ein anderes Objekt mit Referenz beziehen. Bevor ein Asset freigegeben wird, ruft die Java-Laufzeit die Methode finalize () -Methode für das Objekt auf. Diefinalize () auf und hat die folgende allgemeine Form:
Mit dem geschützten Schlüsselwort wird der Zugriff auf finalize () durch Code außerhalb seiner Klasse verhindert. Es ist wichtig zu verstehen, dass finalize () unmittelbar vor der Garbage Collection aufgerufen wird. Es wird beispielsweise nicht aufgerufen, wenn ein Objekt den Bereich verlässt. Dies bedeutet, dass Sie nicht wissen können, wann oder ob finalize () ausgeführt wird. Infolgedessen muss das Programm andere Mittel bereitstellen, um Systemressourcen oder andere vom Objekt verwendete Ressourcen freizugeben. Sie sollten sich nicht auf finalize () verlassen, um das Programm normal auszuführen.
quelle
Klasse, in der wir die Finalisierungsmethode überschreiben
Die Chancen, dass die Finalisierungsmethode aufgerufen wird
Wenn der Speicher mit Dump-Objekten überladen ist, ruft gc die finalize-Methode auf
Führen Sie die Konsole aus, in der die Finalize-Methode nicht häufig aufgerufen wird. Wenn der Speicher überlastet wird, wird die Finalize-Methode aufgerufen.
quelle
Quelle
quelle
finalize()
wird kurz vor der Speicherbereinigung aufgerufen. Es wird nicht aufgerufen, wenn ein Objekt den Gültigkeitsbereich verlässt. Dies bedeutet, dass Sie nicht wissen können, wann oder obfinalize()
sie ausgeführt werden.Beispiel:
Wenn Ihr Programm endet, bevor der Garbage Collector auftritt,
finalize()
wird es nicht ausgeführt. Daher sollte es als Sicherungsverfahren verwendet werden, um den ordnungsgemäßen Umgang mit anderen Ressourcen sicherzustellen, oder für Anwendungen mit besonderer Verwendung, nicht als Mittel, das Ihr Programm im normalen Betrieb verwendet.quelle
Wie in https://wiki.sei.cmu.edu/confluence/display/java/MET12-J.+Do+not+use+finalizers ausgeführt ,
quelle
Versuchen Sie, dieses Programm zum besseren Verständnis auszuführen
quelle