2009-06-16 6 views
15

Was passiert, wenn Sie während des Finalisierungsaufrufs einen Verweis auf das aktuelle Objekt speichern? Zum Beispiel:Referenz zum Objekt während des Finalisierens

class foo { 
    ... 
    public void finalize() { 
     bar.REFERENCE = this; 
    } 
} 

Ist das Objekt Müll gesammelt, oder nicht? Was passiert, wenn Sie später versuchen, auf zuzugreifen?

+4

+1, weil es eine gute Frage ist, aber ich hoffe, das war nur eine intellektuelle Übung. ;) –

+0

mach dir keine Sorgen, es war :) –

Antwort

11

Das Objekt ist nicht Müll gesammelt. Dies ist bekannt als "Object Resurrection".

Sie müssen damit vorsichtig sein, sobald die Finalizerthread die gc nennen es wird nicht wieder genannt wird, auf einigen Umgebungen wie .NET können Sie die Finalizerthread neu registrieren, aber ich bin mir nicht sicher über java

6

Dies ist der Grund, warum die Verwendung von finalize() generell nicht empfohlen wird.

+0

Finalize sollte nur verwendet werden, um Verweise auf nicht verwaltete Ressourcen freizugeben. Der GC wird sich letztendlich um alle verwalteten Referenzen kümmern. –

+6

Nein, finalize sollte NICHT dafür verwendet werden, da es zu einem beliebigen späteren Zeitpunkt oder gar nicht ausgeführt wird. Nicht verwaltete Ressourcen sollten explizit in einem finally-Block freigegeben werden.Im besten Fall kann finalize() eine zusätzliche Fail-safe-Funktion sein. –

+1

... aber auch als Ausfallsicherung ist das sehr problematisch. Da es nicht deterministisch ist, wird es ein reproduzierbares Ressourcenleck in ein intermittierendes Ressourcenleck verwandeln, das weniger häufig auftritt, aber viel schwieriger zu reproduzieren ist. Da gewesen, das getan :-(. – sleske

1

Die finalize()-Methode kann explizit auf der foo Instanz aufgerufen werden, oder es kann von dem Garbage Collector aufgerufen werden, wenn es versucht, den von diesem Objekt belegten Speicher zurückzufordern. Wenn bar eine gültige Instanz ist, wird das Feld REFERENCE auf foo gesetzt. Aus der Sicht des Garbage Collector erhöht dies die Referenzzahl von foo.

Wenn eine Ausnahme innerhalb der finalize() Methode ausgelöst wird (beispielsweise wie ein NullPointerException aufgrund bar wobei null), dann der Finalisierung endet einfach.

N.B. Wie andere darauf hingewiesen haben .. Ihr Beispiel ist definitiv etwas zu vermeiden.

9

Wenn Sie unbedingt Objekte wiederbeleben müssen, schlägt dieser Artikel JavaWorld vor, eine neue Instanz zu erstellen, statt die abgeschlossene Instanz wieder auferstehen zu lassen. Wenn die abgeschlossene Instanz wieder erfasst werden kann, wird sie einfach gesammelt (der Finalizer wird nicht ausgeführt) nochmal).

0

Da Java eine sichere Sprache und Plattform ist, wird der Speicher nicht freigegeben. Auch die zugehörigen PhantomReference s werden nicht in ihre ReferenceQueue s eingereiht. Die VM ruft nur einmal finalize für ein Objekt auf. Es gibt ein nettes Zustandsdiagramm in der JVM-Spezifikation.

Wenn Sie einen Finalisierer verwenden, sollten Sie die Deklaration normalerweise als @Override protected void finalize() throws Throwable belassen, um die API nicht zu stören. Verwenden Sie besser einen abgeschirmten Finalisierer, wie in Effective Java 1st Ed.

Dieser besondere Trick traf die Schlagzeilen (der San Jose Mercury, überhaupt), als eine Gruppe in Princeton es verwendete, um eine benutzerdefinierte ClassLoader aus nicht vertrauenswürdigen Code zu konstruieren. Obwohl die Spezifikation leicht verschärft wurde (der Object-Konstruktor muss die Ausführung normal beenden, bevor der Finalisierer aufgerufen werden kann - angegeben in J2SE 5.0, implementiert in Java SE 6), bleibt dies ein Problembereich. Wenn Sie eine API entwerfen, stellen Sie sicher, dass sensible Klassen keine Unterklassen sein können, und ersparen Sie sich viel Kummer.

Verwandte Themen