Warum sollten Sie finalize () jemals implementieren?


371

Ich habe viele der Rookie-Java-Fragen gelesen finalize()und finde es verwirrend, dass niemand wirklich deutlich gemacht hat, dass finalize () ein unzuverlässiger Weg ist, um Ressourcen zu bereinigen. Ich habe jemanden kommentieren sehen, dass er es verwendet, um Verbindungen zu bereinigen, was wirklich beängstigend ist, da der einzige Weg, um einer Garantie, dass eine Verbindung geschlossen ist, so nahe zu kommen, darin besteht, try (catch) endgültig zu implementieren.

Ich war nicht in CS geschult, aber ich programmiere seit fast einem Jahrzehnt professionell in Java und habe noch nie jemanden gesehen, der finalize()jemals in ein Produktionssystem implementiert wurde. Dies bedeutet immer noch nicht, dass es nicht seinen Nutzen hat oder dass die Leute, mit denen ich zusammengearbeitet habe, es richtig gemacht haben.

Meine Frage ist also, welche Anwendungsfälle gibt es für die Implementierung finalize(), die nicht zuverlässiger über einen anderen Prozess oder eine andere Syntax innerhalb der Sprache behandelt werden können?

Bitte geben Sie bestimmte Szenarien oder Ihre Erfahrungen an. Das einfache Wiederholen eines Java-Lehrbuchs oder die endgültige Verwendung ist nicht ausreichend, da dies nicht die Absicht dieser Frage ist.



2
Die meisten Anwendungs- und Bibliothekscodes werden niemals verwendet finalize(). Allerdings Plattform Bibliothekscode , wie SocketInputStream, die im Namen des Anrufers nativen Ressourcen verwaltet, nicht so zu versuchen , das Risiko von Ressourcenlecks zu minimieren (oder verwendet gleichwertige Mechanismen, wie zum Beispiel PhantomReference, die später hinzugefügt wurden.) Also das Ökosystem sie braucht , obwohl 99,9999% der Entwickler niemals einen schreiben werden.
Brian Goetz

Antworten:


231

Sie können es als Backstop für ein Objekt verwenden, das eine externe Ressource (Socket, Datei usw.) enthält. Implementieren Sie eine close()Methode und ein Dokument, die aufgerufen werden müssen.

Implementieren finalize()Sie die close()Verarbeitung, wenn Sie feststellen, dass sie nicht ausgeführt wurde. Vielleicht mit etwas, stderrum darauf hinzuweisen, dass Sie nach einem fehlerhaften Anrufer aufräumen.

Es bietet zusätzliche Sicherheit in einer außergewöhnlichen / fehlerhaften Situation. Nicht jeder Anrufer wird try {} finally {}jedes Mal die richtigen Dinge tun . Leider, aber in den meisten Umgebungen wahr.

Ich bin damit einverstanden, dass es selten benötigt wird. Und wie Kommentatoren betonen, ist dies mit GC-Overhead verbunden. Verwenden Sie diese Option nur, wenn Sie die Sicherheit "Gürtel und Hosenträger" in einer lang laufenden App benötigen.

Ich sehe, dass ab Java 9 Object.finalize()veraltet ist! Sie weisen uns auf java.lang.ref.Cleanerund java.lang.ref.PhantomReferenceals Alternativen.


44
Stellen Sie einfach sicher, dass eine Ausnahme niemals von finalize () ausgelöst wird. Andernfalls setzt der Garbage Collector die Bereinigung dieses Objekts nicht fort und es kommt zu einem Speicherverlust.
Skaffman

17
Es wird nicht garantiert, dass Finalize aufgerufen wird. Verlassen Sie sich also nicht darauf, dass eine Ressource freigegeben wird.
flicken

19
skaffman - das glaube ich nicht (abgesehen von einer fehlerhaften JVM-Implementierung). Aus dem Object.finalize () -Javadoc: Wenn eine nicht erfasste Ausnahme von der finalize-Methode ausgelöst wird, wird die Ausnahme ignoriert und die Finalisierung dieses Objekts wird beendet.
John M

4
Ihr Vorschlag kann die Fehler von Personen (die nicht in der Nähe sind) für lange Zeit verbergen. Ich würde es nicht empfehlen.
Kohlerm

64
Genau aus diesem Grund habe ich finalize verwendet. Ich habe den Code geerbt und er war sehr fehlerhaft und hatte die Tendenz, Datenbankverbindungen offen zu lassen. Wir haben die Verbindungen so geändert, dass sie Daten darüber enthalten, wann und wo sie erstellt wurden, und dann finalize implementiert, um diese Informationen zu protokollieren, wenn die Verbindung nicht ordnungsgemäß geschlossen wurde. Es stellte sich als große Hilfe heraus, die nicht geschlossenen Verbindungen aufzuspüren.
Brainimus

174

finalize()ist ein Hinweis an die JVM, dass es hilfreich sein könnte, Ihren Code zu einem nicht festgelegten Zeitpunkt auszuführen. Dies ist gut, wenn Code auf mysteriöse Weise nicht ausgeführt werden soll.

In Finalisierern ist es auch in drei Situationen gut, etwas Wichtiges zu tun (im Grunde alles außer Protokollierung):

  • Sie möchten darauf wetten, dass sich andere finalisierte Objekte noch in einem Zustand befinden, den der Rest Ihres Programms für gültig hält.
  • Sie möchten allen Methoden aller Klassen mit einem Finalizer viel Prüfcode hinzufügen, um sicherzustellen, dass sie sich nach der Finalisierung korrekt verhalten.
  • Sie möchten finalisierte Objekte versehentlich wiederbeleben und viel Zeit damit verbringen, herauszufinden, warum sie nicht funktionieren und / oder warum sie nicht finalisiert werden, wenn sie schließlich veröffentlicht werden.

Wenn Sie der Meinung sind, dass Sie finalize () benötigen, möchten Sie manchmal wirklich eine Phantomreferenz (die im angegebenen Beispiel einen harten Verweis auf eine von ihrem Verweis verwendete Verbindung enthalten und diese schließen kann, nachdem die Phantomreferenz in die Warteschlange gestellt wurde). Dies hat auch die Eigenschaft, dass es auf mysteriöse Weise niemals ausgeführt werden kann, aber zumindest keine Methoden für finalisierte Objekte aufrufen oder wiederbeleben kann. Es ist also genau richtig für Situationen, in denen Sie diese Verbindung nicht unbedingt sauber schließen müssen, dies aber gerne möchten und die Kunden Ihrer Klasse sich nicht selbst schließen können oder wollen (was eigentlich fair genug ist - Was' s der Punkt , an alle einen Garbage Collector zu haben , wenn Sie Schnittstellen entwickeln, erfordern eine bestimmte Aktion vor der Entnahme genommen werden? Das versetzt uns in die Zeit von malloc / free zurück.)

In anderen Fällen benötigen Sie die Ressource, die Sie für robuster halten. Warum müssen Sie beispielsweise diese Verbindung schließen? Es muss letztendlich auf einer Art von E / A basieren, die vom System bereitgestellt wird (Socket, Datei, was auch immer). Warum können Sie sich also nicht darauf verlassen, dass das System es für Sie schließt, wenn die niedrigste Ressourcenebene bereitgestellt wird? Wenn der Server am anderen Ende unbedingt verlangt, dass Sie die Verbindung sauber schließen, anstatt nur den Socket fallen zu lassen, was passiert dann, wenn jemand über das Stromkabel des Computers stolpert, auf dem Ihr Code ausgeführt wird, oder wenn das dazwischenliegende Netzwerk ausfällt?

Haftungsausschluss: Ich habe in der Vergangenheit an einer JVM-Implementierung gearbeitet. Ich hasse Finalisierer.


76
Upvoting für extreme Sarkasmusgerechtigkeit.
Wahrnehmung

32
Dies beantwortet die Frage nicht. es sagt nur alle Nachteile von finalize()ohne Angabe von Gründen, die jemand wirklich nutzen möchte.
Mechanische Schnecke

1
@ Supercat: Phantomreferenzen (im Übrigen alle Referenzen) wurden in Java 2 eingeführt
Steve Jessop

1
@supercat: sorry ja, mit "referenzen" meinte ich java.lang.ref.Referenceund seine unterklassen. Java 1 hatte Variablen :-) Und ja, es hatte auch Finalizer.
Steve Jessop

2
@SteveJessop: Wenn ein Basisklassenkonstruktor andere Entitäten auffordert, ihren Status im Namen des zu erstellenden Objekts zu ändern (ein sehr häufiges Muster), ein Feldinitialisierer für abgeleitete Klassen jedoch eine Ausnahme auslöst, sollte das teilweise konstruierte Objekt sofort bereinigt werden nach sich selbst (dh diese externen Entitäten benachrichtigen, dass ihre Dienste nicht mehr benötigt werden), aber weder Java noch .NET bieten ein gleichmäßiges, aus der Ferne sauberes Muster, über das dies geschehen kann. In der Tat scheinen sie sich alle Mühe zu geben, um einen Verweis auf das zu bereinigende Objekt zu erschweren, um den Bereinigungscode zu erreichen.
Supercat

58

Eine einfache Regel: Verwenden Sie niemals Finalizer.

Die Tatsache allein, dass ein Objekt einen Finalizer hat (unabhängig davon, welchen Code es ausführt), reicht aus, um einen erheblichen Overhead für die Speicherbereinigung zu verursachen.

Aus einem Artikel von Brian Goetz:

Objekte mit Finalisierern (solche mit einer nicht trivialen finalize () -Methode) haben im Vergleich zu Objekten ohne Finalisierer einen erheblichen Overhead und sollten sparsam verwendet werden. Finalisierbare Objekte sind sowohl langsamer zuzuweisen als auch langsamer zu sammeln. Zur Zuweisungszeit muss die JVM alle finalisierbaren Objekte beim Garbage Collector registrieren, und (zumindest in der HotSpot JVM-Implementierung) finalisierbare Objekte müssen einem langsameren Zuweisungspfad folgen als die meisten anderen Objekte. In ähnlicher Weise sind finalisierbare Objekte auch langsamer zu sammeln. Es dauert mindestens zwei Garbage Collection-Zyklen (im besten Fall), bis ein finalisierbares Objekt zurückgefordert werden kann, und der Garbage Collector muss zusätzliche Arbeit leisten, um den Finalizer aufzurufen. Das Ergebnis ist mehr Zeit für das Zuweisen und Sammeln von Objekten und mehr Druck auf den Garbage Collector, da der von nicht erreichbaren finalisierbaren Objekten verwendete Speicher länger erhalten bleibt. Kombinieren Sie dies mit der Tatsache, dass Finalizer nicht garantiert in einem vorhersehbaren Zeitrahmen oder überhaupt nicht ausgeführt werden können, und Sie sehen, dass es relativ wenige Situationen gibt, für die die Finalisierung das richtige Werkzeug ist.


46

Das einzige Mal, dass ich finalize im Produktionscode verwendet habe, war die Überprüfung, ob die Ressourcen eines bestimmten Objekts bereinigt wurden, und wenn nicht, eine sehr lautstarke Nachricht zu protokollieren. Es hat nicht wirklich versucht, es selbst zu tun, es hat nur viel geschrien, wenn es nicht richtig gemacht wurde. Es stellte sich als sehr nützlich heraus.


35

Ich mache Java seit 1998 professionell und habe es nie implementiert finalize(). Nicht einmal.


Wie zerstöre ich dann das Objekt der öffentlichen Klasse? Es verursacht Probleme in ADF. Grundsätzlich wird angenommen, dass die Seite neu
geladen wird

2
@ InfantPro'Aravind 'Aufruf finalize entfernt das Objekt nicht. Es ist eine Methode, die Sie implementieren und die die JVM aufrufen kann, wenn Ihr Objekt durch Müll gesammelt wird.
Paul Tomblin

@ PaulTomblin, ohk danke für das Detail. Irgendwelche Vorschläge zum Aktualisieren einer Seite in ADF?
InfantPro'Aravind '

@ InfantPro'Aravind 'Keine Ahnung, nie ADF verwendet.
Paul Tomblin

28

Die akzeptierte Antwort ist gut. Ich wollte nur hinzufügen, dass es jetzt eine Möglichkeit gibt, die Funktionalität des Finalisierens zu nutzen, ohne sie überhaupt zu verwenden.

Schauen Sie sich die "Referenz" -Klassen an. Schwache Referenz, Phantomreferenz und weiche Referenz.

Sie können sie verwenden, um einen Verweis auf alle Ihre Objekte zu behalten, aber dieser Verweis ALLEIN beendet GC nicht. Das Schöne daran ist, dass Sie eine Methode aufrufen lassen können, wenn sie gelöscht wird, und dass diese Methode garantiert aufgerufen werden kann.

Zum Finalisieren: Ich habe finalize einmal verwendet, um zu verstehen, welche Objekte freigegeben wurden. Sie können einige nette Spiele mit Statik, Referenzzählung und dergleichen spielen - aber es war nur zur Analyse gedacht, aber achten Sie auf Code wie diesen (nicht nur beim Finalisieren, sondern dort, wo Sie ihn am wahrscheinlichsten sehen werden):

public void finalize() {
  ref1 = null;
  ref2 = null;
  othercrap = null;
}

Es ist ein Zeichen dafür, dass jemand nicht wusste, was er tat. Ein solches "Aufräumen" ist praktisch nie erforderlich. Wenn die Klasse GC-fähig ist, erfolgt dies automatisch.

Wenn Sie einen solchen Code in einem Final finden, ist garantiert, dass die Person, die ihn geschrieben hat, verwirrt war.

Wenn es anderswo ist, kann es sein, dass der Code ein gültiger Patch für ein schlechtes Modell ist (eine Klasse bleibt lange bestehen und aus irgendeinem Grund mussten die Dinge, auf die sie verweist, manuell freigegeben werden, bevor das Objekt GC-fähig ist). Im Allgemeinen liegt es daran, dass jemand vergessen hat, einen Listener oder etwas zu entfernen, und nicht herausfinden kann, warum sein Objekt nicht GC-fähig ist. Deshalb löscht er einfach die Dinge, auf die er sich bezieht, und zuckt mit den Schultern und geht weg.

Es sollte niemals verwendet werden, um Dinge "schneller" aufzuräumen.


3
Ich denke, Phantomreferenzen sind eine bessere Möglichkeit, um zu verfolgen, welche Objekte freigegeben werden.
Bill Michell

2
Upvoting für die beste Erklärung für "schwache Referenz", die ich je gehört habe.
sscarduzio

Es tut mir leid, dass ich so viele Jahre gebraucht habe, um dies zu lesen, aber es ist wirklich eine schöne Ergänzung zu den Antworten.
Spencer Kormos

27

Ich bin mir nicht sicher, was Sie daraus machen können, aber ...

itsadok@laptop ~/jdk1.6.0_02/src/
$ find . -name "*.java" | xargs grep "void finalize()" | wc -l
41

Ich denke, die Sonne hat einige Fälle gefunden, in denen sie verwendet werden sollte.


12
Ich denke, es ist auch eine Frage von "Wird Sun-Entwickler immer Recht haben"?
CodeReaper

13
Aber für wie viele dieser Anwendungen wird die Unterstützung nur implementiert oder getestet, finalizeanstatt sie tatsächlich zu verwenden?
Mechanische Schnecke

Ich benutze Windows. Wie würden Sie dasselbe in Windows tun?
Gparyani

2
@damryfbfnetsi: Versuchen ack Installation ( beyondgrep.com ) , über chocolatey.org/packages/ack . Oder verwenden Sie eine einfache Funktion zum Suchen in Dateien in $FAVORITE_IDE.
Brian Cline

21
class MyObject {
    Test main;

    public MyObject(Test t) {    
        main = t; 
    }

    protected void finalize() {
        main.ref = this; // let instance become reachable again
        System.out.println("This is finalize"); //test finalize run only once
    }
}

class Test {
    MyObject ref;

    public static void main(String[] args) {
        Test test = new Test();
        test.ref = new MyObject(test);
        test.ref = null; //MyObject become unreachable,finalize will be invoked
        System.gc(); 
        if (test.ref != null) System.out.println("MyObject still alive!");  
    }
}

===================================

Ergebnis:

This is finalize

MyObject still alive!

=====================================

Sie können also eine nicht erreichbare Instanz in der Finalisierungsmethode erreichbar machen.


21
Aus irgendeinem Grund lässt mich dieser Code an Zombie-Filme denken. Sie GC Ihr Objekt und dann steht es wieder auf ...
steveha

oben ist gute Codes. Ich habe mich gefragt, wie ich das Objekt gerade jetzt wieder erreichbar machen kann.
lwpro2

15
Nein, oben sind schlechte Codes. Es ist ein Beispiel dafür, warum Finalisieren schlecht ist.
Tony

Denken Sie daran, dass das Aufrufen System.gc();keine Garantie dafür ist, dass der Garbage Collector tatsächlich ausgeführt wird. Es liegt im alleinigen Ermessen des GC, den Heap zu bereinigen (möglicherweise noch genügend freier Heap, möglicherweise nicht zu stark fragmentiert, ...). Es ist also nur eine bescheidene Bitte des Programmierers: "Bitte, könnten Sie mich anhören und rennen?" und kein Befehl "lauf jetzt wie ich sage!". Es tut uns leid, dass Sie linguale Wörter verwenden, aber es sagt genau, wie der GC der JVM funktioniert.
Roland

10

finalize()kann nützlich sein, um Ressourcenlecks zu erkennen. Wenn die Ressource geschlossen werden soll, aber nicht geschrieben wird, schreiben Sie die Tatsache, dass sie nicht geschlossen wurde, in eine Protokolldatei und schließen Sie sie. Auf diese Weise entfernen Sie das Ressourcenleck und können selbst feststellen, dass es aufgetreten ist, damit Sie es beheben können.

Ich programmiere seit 1.0 alpha 3 (1995) in Java und muss noch finalize für irgendetwas überschreiben ...


6

Sie sollten sich nicht auf finalize () verlassen, um Ihre Ressourcen für Sie zu bereinigen. finalize () wird dann erst ausgeführt, wenn die Klasse durch Müll gesammelt wurde. Es ist viel besser, Ressourcen explizit freizugeben, wenn Sie sie nicht mehr verwenden.


5

Um einen Punkt in den obigen Antworten hervorzuheben: Finalizer werden auf dem einzelnen GC-Thread ausgeführt. Ich habe von einer großen Sun-Demo gehört, bei der die Entwickler einigen Finalisierern einen kleinen Schlaf verliehen und absichtlich eine ansonsten ausgefallene 3D-Demo in die Knie gezwungen haben.

Am besten vermeiden, mit möglicher Ausnahme der Test-Env-Diagnose.

Eckels Denken in Java hat einen guten Abschnitt dazu.


4

Hmmm, ich habe es einmal verwendet, um Objekte zu bereinigen, die nicht in einen vorhandenen Pool zurückgegeben wurden.

Sie wurden viel herumgereicht, so dass es unmöglich war zu sagen, wann sie sicher in den Pool zurückgebracht werden konnten. Das Problem war, dass es während der Speicherbereinigung eine enorme Strafe gab, die weitaus größer war als die Einsparungen durch das Zusammenlegen der Objekte. Es war ungefähr einen Monat in Produktion, bevor ich den ganzen Pool herausriss, alles dynamisch machte und damit fertig war.


4

Seien Sie vorsichtig mit dem, was Sie in einem tun finalize(). Vor allem, wenn Sie es beispielsweise für den Aufruf von close () verwenden, um sicherzustellen, dass die Ressourcen bereinigt werden. Wir hatten mehrere Situationen, in denen JNI-Bibliotheken mit dem laufenden Java-Code verknüpft waren, und unter allen Umständen, in denen wir finalize () zum Aufrufen von JNI-Methoden verwendet haben, kam es zu einer sehr schlechten Beschädigung des Java-Heaps. Die Beschädigung wurde nicht durch den zugrunde liegenden JNI-Code selbst verursacht, alle Speicherspuren in den nativen Bibliotheken waren in Ordnung. Es war nur die Tatsache, dass wir JNI-Methoden von finalize () überhaupt aufgerufen haben.

Dies war mit einem JDK 1.5, das immer noch weit verbreitet ist.

Wir würden erst viel später herausfinden, dass etwas schief gelaufen ist, aber am Ende war der Schuldige immer die finalize () -Methode, die JNI-Aufrufe verwendete.


3

Beim Schreiben von Code, der von anderen Entwicklern verwendet wird, muss eine Art "Bereinigungs" -Methode aufgerufen werden, um Ressourcen freizugeben. Manchmal vergessen diese anderen Entwickler, Ihre Bereinigungsmethode (oder die Methode zum Schließen oder Zerstören oder was auch immer) aufzurufen. Um mögliche Ressourcenlecks zu vermeiden, können Sie die finalize-Methode überprüfen, um sicherzustellen, dass die Methode aufgerufen wurde. Wenn dies nicht der Fall ist, können Sie sie selbst aufrufen.

Viele Datenbanktreiber tun dies in ihren Statement- und Connection-Implementierungen, um ein wenig Sicherheit gegen Entwickler zu bieten, die vergessen haben, sie zu schließen.


2

Edit: Okay, es funktioniert wirklich nicht. Ich habe es implementiert und dachte, wenn es manchmal fehlschlägt, ist das für mich in Ordnung, aber es hat nicht einmal die Finalize-Methode ein einziges Mal aufgerufen.

Ich bin kein professioneller Programmierer, aber in meinem Programm habe ich einen Fall, den ich für ein gutes Beispiel für die Verwendung von finalize () halte, dh einen Cache, der seinen Inhalt auf die Festplatte schreibt, bevor er zerstört wird. Da es nicht notwendig ist, dass es jedes Mal bei Zerstörung ausgeführt wird, beschleunigt es nur mein Programm. Ich hoffe, dass ich es nicht falsch gemacht habe.

@Override
public void finalize()
{
    try {saveCache();} catch (Exception e)  {e.printStackTrace();}
}

public void saveCache() throws FileNotFoundException, IOException
{
    ObjectOutputStream out = new ObjectOutputStream(new FileOutputStream("temp/cache.tmp"));
    out.writeObject(cache);
}

Ich denke, ein Cache (von dem Typ, den Sie auf die Festplatte leeren würden) ist ein gutes Beispiel. Und selbst wenn finalize nicht aufgerufen wird, kein Schweiß.
foo

2

Es kann nützlich sein, Dinge zu entfernen, die einem globalen / statischen Ort hinzugefügt wurden (nicht erforderlich) und entfernt werden müssen, wenn das Objekt entfernt wird. Zum Beispiel:

    private void addGlobalClickListener () {
        schwachAwtEventListener = neuer WeakAWTEventListener (this);

        Toolkit.getDefaultToolkit (). AddAWTEventListener (schwachAwtEventListener, AWTEvent.MOUSE_EVENT_MASK);
    }}

    @Override
    protected void finalize () wirft Throwable {
        super.finalize ();

        if (schwachAwtEventListener! = null) {
            Toolkit.getDefaultToolkit (). RemoveAWTEventListener (schwachAwtEventListener);
        }}
    }}

Dies erfordert zusätzliche Anstrengungen, da, wenn der Listener einen starken Verweis auf die thisim Konstruktor an ihn übergebene Instanz hat, diese Instanz niemals unerreichbar wird und daher finalize()ohnehin nie bereinigt wird. Wenn der Listener andererseits einen schwachen Verweis auf dieses Objekt hat, wie der Name schon sagt, besteht die Gefahr, dass dieses Konstrukt zu Zeiten bereinigt wird, in denen dies nicht der Fall sein sollte. Objektlebenszyklen sind nicht das richtige Werkzeug für die Implementierung der Anwendungssemantik.
Holger

0

iirc - Sie können die Finalize-Methode verwenden, um einen Pooling-Mechanismus für teure Ressourcen zu implementieren. Sie erhalten also auch keine GCs.


0

Als Anmerkung:

Ein Objekt, das finalize () überschreibt, wird vom Garbage Collector speziell behandelt. Normalerweise wird ein Objekt während des Erfassungszyklus sofort zerstört, nachdem sich das Objekt nicht mehr im Gültigkeitsbereich befindet. Finalisierbare Objekte werden jedoch stattdessen in eine Warteschlange verschoben, in der separate Finalisierungsthreads die Warteschlange entleeren und die finalize () -Methode für jedes Objekt ausführen. Sobald die finalize () -Methode beendet ist, ist das Objekt im nächsten Zyklus endlich für die Speicherbereinigung bereit.

Quelle: finalize () ist auf Java-9 veraltet


0

Die Ressourcen (Datei, Socket, Stream usw.) müssen geschlossen werden, sobald wir damit fertig sind. Sie haben im Allgemeinen eine close()Methode, die wir im finallyAbschnitt von try-catchAnweisungen allgemein aufrufen . Manchmal finalize()kann es auch von wenigen Entwicklern verwendet werden, aber IMO ist kein geeigneter Weg, da es keine Garantie dafür gibt, dass finalize immer aufgerufen wird.

In Java 7 haben wir eine Try-with-Resources- Anweisung, die wie folgt verwendet werden kann:

try (BufferedReader br = new BufferedReader(new FileReader(path))) {
  // Processing and other logic here.
} catch (Exception e) {
  // log exception
} finally {
  // Just in case we need to do some stuff here.
}

Im obigen Beispiel schließt try-with-resource die Ressource automatisch BufferedReaderdurch Aufrufen der close()Methode. Wenn wir möchten, können wir Closeable auch in unseren eigenen Klassen implementieren und auf ähnliche Weise verwenden. IMO scheint es ordentlicher und einfacher zu verstehen.


0

Persönlich habe ich fast nie verwendet, finalize()außer in einem seltenen Fall: Ich habe eine benutzerdefinierte generische Sammlung erstellt und eine benutzerdefinierte finalize()Methode geschrieben, die Folgendes bewirkt:

public void finalize() throws Throwable {
    super.finalize();
    if (destructiveFinalize) {
        T item;
        for (int i = 0, l = length(); i < l; i++) {
            item = get(i);
            if (item == null) {
                continue;
            }
            if (item instanceof Window) {
                ((Window) get(i)).dispose();
            }
            if (item instanceof CompleteObject) {
                ((CompleteObject) get(i)).finalize();
            }
            set(i, null);
        }
    }
}

( CompleteObjectIst eine Schnittstelle ich gemacht, mit dem Sie festlegen , dass Sie nur selten implementierter implementiert haben ObjectMethoden wie #finalize(), #hashCode()und #clone())

Mit einer Schwestermethode #setDestructivelyFinalizes(boolean)kann das Programm, das meine Sammlung verwendet, (Hilfe) garantieren, dass durch das Zerstören eines Verweises auf diese Sammlung auch Verweise auf deren Inhalt zerstört werden und alle Fenster entfernt werden, die die JVM möglicherweise unbeabsichtigt am Leben erhalten. Ich überlegte auch, irgendwelche Fäden zu stoppen, aber das öffnete eine ganz neue Dose Würmer.


4
Wenn Sie finalize()Ihre CompleteObjectInstanzen wie im obigen Code aufrufen, wird sie möglicherweise zweimal aufgerufen, da die JVM möglicherweise immer noch aufgerufen wird, finalize()sobald diese Objekte tatsächlich nicht mehr erreichbar sind. Dies liegt aufgrund der Logik der Finalisierung möglicherweise vor der finalize()Methode Ihrer speziellen Sammlung wird gleichzeitig oder sogar gleichzeitig angerufen. Da ich in Ihrer Methode keine Maßnahmen zur Gewährleistung der Thread-Sicherheit sehe, scheinen Sie sich dessen nicht bewusst zu sein ...
Holger

0

Die akzeptierte Antwort listet auf, dass das Schließen einer Ressource während des Finalisierens erfolgen kann.

Diese Antwort zeigt jedoch, dass zumindest in Java8 mit dem JIT-Compiler unerwartete Probleme auftreten, bei denen manchmal der Finalizer aufgerufen wird, noch bevor Sie mit dem Lesen aus einem von Ihrem Objekt verwalteten Stream fertig sind.

Selbst in dieser Situation wäre es nicht empfehlenswert , finalize aufzurufen .


Es würde funktionieren, wenn die Operation threadsicher gemacht wird, was ein Muss ist, da Finalizer von beliebigen Threads aufgerufen werden können. Da eine korrekt implementierte Thread-Sicherheit bedeutet, dass nicht nur die Schließoperation, sondern auch die Operationen, die die Ressource verwenden, für dasselbe Objekt oder dieselbe Sperre synchronisiert werden müssen, besteht eine Beziehung zwischen der Verwendung und der Schließoperation, die ebenfalls zu früh verhindert Finalisierung. Aber natürlich zu einem hohen Preis für die gesamte Nutzung…
Holger
Durch die Nutzung unserer Website bestätigen Sie, dass Sie unsere Cookie-Richtlinie und Datenschutzrichtlinie gelesen und verstanden haben.
Licensed under cc by-sa 3.0 with attribution required.