Java Virtual Machine - Speicherbereinigung
Der Lebenszyklus eines Java-Objekts wird von der JVM verwaltet. Sobald ein Objekt vom Programmierer erstellt wurde, müssen wir uns nicht mehr um den Rest seines Lebenszyklus kümmern. Die JVM findet automatisch die Objekte, die nicht mehr verwendet werden, und fordert ihren Speicher vom Heap zurück.
Die Speicherbereinigung ist eine wichtige Operation, die JVM ausführt, und die Anpassung an unsere Anforderungen kann unserer Anwendung massive Leistungssteigerungen bringen. Es gibt eine Vielzahl von Garbage Collection-Algorithmen, die von modernen JVMs bereitgestellt werden. Wir müssen uns der Bedürfnisse unserer Anwendung bewusst sein, um zu entscheiden, welcher Algorithmus verwendet werden soll.
Sie können ein Objekt in Java nicht programmgesteuert freigeben, wie dies in Nicht-GC-Sprachen wie C und C ++ der Fall ist. Daher können Sie in Java keine baumelnden Referenzen haben. Möglicherweise haben Sie jedoch Nullreferenzen (Referenzen, die sich auf einen Speicherbereich beziehen, in dem die JVM niemals Objekte speichert). Immer wenn eine Nullreferenz verwendet wird, löst die JVM eine NullPointerException aus.
Beachten Sie, dass es in Java-Programmen dank des GC zwar selten zu Speicherlecks kommt, diese jedoch auftreten. Wir werden am Ende dieses Kapitels einen Speicherverlust verursachen.
Die folgenden GCs werden in modernen JVMs verwendet
- Serienkollektor
- Durchsatzkollektor
- CMS-Sammler
- G1 Sammler
Jeder der oben genannten Algorithmen führt dieselbe Aufgabe aus: Suchen von Objekten, die nicht mehr verwendet werden, und Wiederherstellen des Speichers, den sie im Heap belegen. Einer der naiven Ansätze hierfür wäre, die Anzahl der Referenzen zu zählen, die jedes Objekt hat, und es freizugeben, sobald die Anzahl der Referenzen 0 wird (dies wird auch als Referenzzählung bezeichnet). Warum ist das naiv? Betrachten Sie eine zirkuläre verknüpfte Liste. Jeder seiner Knoten hat einen Verweis darauf, aber das gesamte Objekt wird nicht von irgendwoher referenziert und sollte im Idealfall freigegeben werden.
Die JVM gibt nicht nur den Speicher frei, sondern verschmilzt auch kleine Speicher-Chucks zu größeren. Dies geschieht, um eine Speicherfragmentierung zu verhindern.
Ein typischer GC-Algorithmus führt einfach die folgenden Aktivitäten aus:
- Nicht verwendete Objekte finden
- Geben Sie den Speicher frei, den sie auf dem Haufen belegen
- Verschmelzen der Fragmente
Der GC muss Anwendungsthreads stoppen, während er ausgeführt wird. Dies liegt daran, dass die Objekte beim Ausführen verschoben werden und diese Objekte daher nicht verwendet werden können. Solche Stopps werden als "Stop-the-World-Pausen" bezeichnet. Die Minimierung der Häufigkeit und Dauer dieser Pausen ist unser Ziel, während wir unseren GC optimieren.
Memory Coalescing
Eine einfache Demonstration der Speicherzusammenführung ist unten dargestellt
Der schattierte Teil sind Objekte, die freigegeben werden müssen. Selbst wenn der gesamte Speicherplatz zurückgefordert wird, können wir nur ein Objekt mit einer maximalen Größe von 75 KB zuweisen. Dies gilt auch dann, wenn wir 200 KB freien Speicherplatz haben, wie unten gezeigt