Effektives Java sagt:
Die Verwendung von Finalizern ist mit erheblichen Leistungseinbußen verbunden.
Warum ist es langsamer, ein Objekt mit den Finalizern zu zerstören?
Effektives Java sagt:
Die Verwendung von Finalizern ist mit erheblichen Leistungseinbußen verbunden.
Warum ist es langsamer, ein Objekt mit den Finalizern zu zerstören?
Das liegt an der Funktionsweise des Garbage Collectors. Aus Leistungsgründen verwenden die meisten Java-GCs einen Kopiersammler, bei dem kurzlebige Objekte einem "eden"-Speicherblock zugewiesen werden. Wenn es an der Zeit ist, diese Generation von Objekten einzusammeln, muss der GC nur die noch "lebenden" Objekte in einen dauerhafteren Speicherbereich kopieren und kann dann den gesamten "eden"-Speicherblock auf einmal löschen (freigeben). Dies ist effizient, da der meiste Java-Code viele Tausende von Instanzen von Objekten (Boxed Primitives, temporäre Arrays usw.) mit einer Lebensdauer von nur wenigen Sekunden erzeugt.
Wenn jedoch Finalizer im Spiel sind, kann der GC nicht einfach eine ganze Generation auf einmal löschen. Stattdessen muss er alle Objekte in dieser Generation ermitteln, die finalisiert werden müssen, und sie in eine Warteschlange auf einem Thread einreihen, der die Finalizer tatsächlich ausführt. In der Zwischenzeit kann der GC das Aufräumen der Objekte nicht effizient abschließen. Also muss er sie entweder länger am Leben halten, als sie sollten, oder er muss das Sammeln anderer Objekte verzögern, oder beides. Hinzu kommt die willkürliche Wartezeit für die tatsächliche Ausführung der Finalizer.
All diese Faktoren summieren sich zu einem erheblichen Laufzeitverlust, weshalb die deterministische Finalisierung (unter Verwendung einer close()
Methode oder ähnliches, um den Zustand des Objekts explizit zu finalisieren) ist normalerweise vorzuziehen.
Ich bin tatsächlich auf ein solches Problem gestoßen:
In der Sun HotSpot JVM werden Finalizer auf einem Thread verarbeitet, der eine feste, niedrige Priorität hat. In einer Anwendung mit hoher Last ist es einfach, Objekte, die für die Finalisierung erforderlich sind, schneller zu erstellen, als der Finalisierungs-Thread mit niedriger Priorität sie verarbeiten kann. In der Zwischenzeit steht der Platz auf dem Heap, der von den zur Finalisierung anstehenden Objekten belegt wird, für andere Zwecke nicht zur Verfügung. Schließlich kann es passieren, dass Ihre Anwendung die gesamte Zeit mit Garbage Collecting verbringt, weil der gesamte verfügbare Speicher von Objekten genutzt wird, die zur Finalisierung anstehen.
Dies gilt natürlich zusätzlich zu den vielen anderen Gründen, keine Finalizer zu verwenden, die in Effective Java beschrieben sind.
Ich habe gerade mein Exemplar von Effective Java von meinem Schreibtisch genommen, um zu sehen, worauf er sich bezieht.
In Kapitel 2, Abschnitt 6, geht er sehr ausführlich auf die verschiedenen Leistungsmerkmale ein.
You can't know when the finalizer will run, or even if it will at all. Because those resources may never be claimed, you will have to run with fewer resources.
Ich würde empfehlen, den gesamten Abschnitt zu lesen - er erklärt die Dinge viel besser, als ich sie hier wiedergeben kann.
Wenn Sie die Dokumentation von finalisieren() Wenn Sie genau hinschauen, werden Sie feststellen, dass Finalizer es einem Objekt ermöglichen, die Abholung durch den GC zu verhindern.
Wenn kein Finalizer vorhanden ist, kann das Objekt einfach entfernt werden und muss nicht weiter beachtet werden. Wenn jedoch ein Finalizer vorhanden ist, muss anschließend überprüft werden, ob das Objekt nicht wieder "sichtbar" geworden ist.
Ohne genau zu wissen, wie die aktuelle Java-Garbage-Collection implementiert ist (da es verschiedene Java-Implementierungen gibt, gibt es auch verschiedene GCs), kann man davon ausgehen, dass die GC aufgrund dieses Merkmals etwas zusätzliche Arbeit leisten muss, wenn ein Objekt einen Finalizer hat.
Mein Gedanke ist folgender: Java ist eine Garbage-Collecting-Sprache, die den Speicher auf der Grundlage ihrer eigenen internen Algorithmen freigibt. Von Zeit zu Zeit durchsucht der GC den Heap, stellt fest, welche Objekte nicht mehr referenziert werden, und gibt den Speicher frei. Ein Finalizer unterbricht diesen Vorgang und erzwingt die Freigabe von Speicher außerhalb des GC-Zyklus, was zu Ineffizienzen führen kann. Ich denke, dass es am besten ist, Finalizer nur dann zu verwenden, wenn es ABSOLUT notwendig ist, wie z.B. das Freigeben von Datei-Handles oder das Schließen von DB-Verbindungen, die deterministisch durchgeführt werden sollten.
CodeJaeger ist eine Gemeinschaft für Programmierer, die täglich Hilfe erhalten..
Wir haben viele Inhalte, und Sie können auch Ihre eigenen Fragen stellen oder die Fragen anderer Leute lösen.