[Java-Interview – JVM und Tuning]

 

Die virtuelle JVM-Maschine hängt mit der Optimierung zusammen.

 5.1 Klassenlademechanismus

 Klassenladelebenszyklus?

Der Klassenladeprozess umfasstLaden, Verifizieren, Vorbereiten, Parsen und Initialisieren fünf Phasen. Unter diesen fünf Phasen ist die Reihenfolge, in der die vier Phasen Laden, Verifizieren, Vorbereiten und Initialisieren auftreten, deterministisch, während dies bei der Analysephase nicht unbedingt der Fall ist. In einigen Fällen kann sie nach der Initialisierungsphase beginnen. Dies dient der Unterstützung der Java Language-Laufzeit Bindung (auch dynamische Bindung oder späte Bindung genannt)*. Beachten Sie auch, dass die verschiedenen Phasen hier der Reihe nach gestartet und nicht der Reihe nach abgeschlossen oder abgeschlossen werden, da diese Phasen normalerweise verschachtelt und miteinander vermischt sind und normalerweise während der Ausführung einer Phase eine andere Phase aufrufen oder aktivieren.

  • Klassenladen: Suchen und laden Sie die Binärdaten der Klasse
  • verbinden
    • Überprüfung: Stellen Sie sicher, dass die geladenen Klassen korrekt sind
    • Vorbereitung: Reservieren Sie Speicher für die statischen Variablen der Klasse und initialisieren Sie sie mit Standardwerten
    • Parsen: Konvertieren Sie Symbolreferenzen in der Klasse in direkte Referenzen
  • Initialisierung: Weisen Sie den statischen Variablen der Klasse korrekte Anfangswerte zu. Die JVM ist für die Initialisierung der Klasse verantwortlich, hauptsächlich für die Initialisierung der Klassenvariablen.
  • Verwendung: Die Schnittstelle der Klasse greift auf die Datenstruktur im Methodenbereich zu, das Objekt sind die Daten im Heap-Bereich
  • Deinstallieren: Lebenszyklus beenden
 Klassenlader-Hierarchie?
  • Klassenlader starten: Bootstrap ClassLoader, verantwortlich für das Laden und Speichern in JDK\jre\lib (JDK stellt das JDK-Installationsverzeichnis dar, dasselbe unten) oder angegeben durch - Xbootclasspath-Parameter Eine Klassenbibliothek, die sich im Pfad befindet und von der virtuellen Maschine erkannt werden kann (z. B. rt.jar, alle Klassen, die mit java.* beginnen, werden vom Bootstrap ClassLoader geladen). Der Startklassenlader kann von Java-Programmen nicht direkt referenziert werden.

  • Extension ClassLoader: Erweiterung ClassLoader, die vonsun.misc.Launcher$ExtClassLoader implementiert wird und für das Laden des JDK\jre\lib\ext-Verzeichnisses verantwortlich ist. Oder für Für alle Klassenbibliotheken im durch die Systemvariablen java.ext.dirs angegebenen Pfad (z. B. Klassen, die mit javax.* beginnen) können Entwickler den Erweiterungsklassenlader direkt verwenden.

  • Application Class Loader: Application ClassLoader, der vonsun.misc.Launcher$AppClassLoader implementiert wird und für das Laden des Benutzerklassenpfads (ClassPath) verantwortlich ist. Für einen angegebenen Klasse können Entwickler diesen Klassenlader direkt verwenden. Wenn die Anwendung keinen eigenen Klassenlader angepasst hat, ist dies im Allgemeinen der Standard-Klassenlader im Programm.

  • Benutzerdefinierter Klassenlader: Da der mit der JVM gelieferte ClassLoader nur weiß, wie Standard-Java-Klassendateien aus dem lokalen Dateisystem geladen werden, können Sie dies tun, wenn Sie Ihren eigenen ClassLoader schreiben Gehen Sie wie folgt vor:

    • Überprüfen Sie digitale Signaturen automatisch, bevor Sie nicht vertrauenswürdigen Code ausführen.
    • Erstellen Sie dynamisch benutzerdefinierte Build-Klassen, die Ihren spezifischen Anforderungen entsprechen.
    • Beziehen Sie Java-Klassen von bestimmten Orten, z. B. Datenbanken und Netzwerken.
 Was ist der Unterschied zwischen Class.forName() und ClassLoader.loadClass()?
  • Class.forName(): Zusätzlich zum Laden der .class-Datei der Klasse in die JVM wird die Klasse auch interpretiert und der statische Block in der Klasse wird ausgeführt.
  • ClassLoader.loadClass(): Es macht nur eine Sache, nämlich das Laden der .class-Datei in die JVM. Der Inhalt in der Statik wird nicht ausgeführt. Der statische Block wird nur in newInstance ausgeführt.
  • Class.forName(name, initialize, loader)Funktionen mit Parametern können auch steuern, ob statische Blöcke geladen werden. Und nur wenn die Methode newInstance() aufgerufen wird, wird der Konstruktor aufgerufen, um ein Objekt der Klasse zu erstellen.
 Über welche Klassenlademechanismen verfügt die JVM?
  • Was sind die JVM-Klassenlademechanismen?
  1. Volle Verantwortung: Wenn ein Klassenlader für das Laden einer Klasse verantwortlich ist, werden andere Klassen, von denen die Klasse abhängt, und Referenzen ebenfalls vom Klassenlader geladen, es sei denn, Show verwendet einen anderen Klassenlader zum Laden
  2. Delegierter der übergeordneten Klasse: Lassen Sie zuerst den Lader der übergeordneten Klasse versuchen, die Klasse zu laden, und versuchen Sie nur, die Klasse aus ihrem eigenen Klassenpfad zu laden, wenn der Lader der übergeordneten Klasse die Klasse nicht laden kann Klasse. Klasse
  3. Caching-Mechanismus, der Caching-Mechanismus stellt sicher, dass alle geladenen Klassen zwischengespeichert werden. Wenn eine bestimmte Klasse im Programm verwendet werden muss, sucht der Klassenlader zuerst nach der Klasse im Cache-Bereich.Klasse: Nur wenn der Cache-Bereich nicht vorhanden ist, liest das System die der Klasse entsprechenden Binärdaten, konvertiert sie in ein Klassenobjekt und speichert sie im Cache-Bereich. Aus diesem Grund müssen Sie nach dem Ändern der Klasse die JVM neu starten, damit die Programmänderung wirksam wird
  4. Parentaler Delegierungsmechanismus: Wenn ein Klassenlader eine Klassenladeanforderung empfängt, versucht er nicht, zuerst die Klasse selbst zu laden, sondern delegiert die Anforderung an den übergeordneten Lader. Zum Abschluss: In der Reihenfolge nach oben sollten daher alle Anforderungen zum Laden von Klassen schließlich an den Startklassenlader der obersten Ebene weitergeleitet werden, und zwar nur dann, wenn der übergeordnete Lader die erforderliche Klasse nicht in seinem Suchbereich findet, d. h. er kann den Ladevorgang nicht abschließen, den Subloader wird versuchen, die Klasse selbst zu laden.
  • Prozess des übergeordneten Delegationsmechanismus?
  1. Wenn AppClassLoader eine Klasse lädt, versucht er zunächst nicht, die Klasse selbst zu laden, sondern delegiert die Klassenladeanforderung zur Fertigstellung an den übergeordneten Klassenlader ExtClassLoader.
  2. Wenn ExtClassLoader eine Klasse lädt, versucht er nicht, zuerst die Klasse selbst zu laden, sondern delegiert die Klassenladeanforderung zur Fertigstellung an BootStrapClassLoader.
  3. Wenn BootStrapClassLoader nicht geladen werden kann (z. B. weil die Klasse nicht in $JAVA_HOME/jre/lib gefunden wird), wird ExtClassLoader verwendet, um zu versuchen, zu laden.
  4. Wenn ExtClassLoader ebenfalls nicht geladen werden kann, wird AppClassLoader zum Laden verwendet. Wenn AppClassLoader ebenfalls nicht geladen werden kann, wird eine Ausnahme ClassNotFoundException gemeldet.

 5.2 Speicherstruktur

 Sprechen Sie über die Gesamtstruktur des JVM-Speichers? Sind Threads privat oder geteilt?

Der mittlere Teil der gesamten JVM-Architektur sind die verschiedenen Laufzeitdatenbereiche, die von der Java Virtual Machine definiert werden.

Die Java Virtual Machine definiert mehrere Laufzeitdatenbereiche, die während der Programmausführung verwendet werden. Einige davon werden beim Start der virtuellen Maschine erstellt und beim Beenden der virtuellen Maschine zerstört. Andere haben eine Eins-zu-Eins-Entsprechung mit Threads. Diese Datenbereiche, die Threads entsprechen, werden erstellt und zerstört, wenn der Thread beginnt und endet.

  • Thread privat: Programmzähler, Stapel der virtuellen Maschine, lokaler Methodenbereich
  • Thread-Sharing: Heap, Methodenbereich, Off-Heap-Speicher (permanente Generierung von Java7 oder Metaspace von JDK8, Code-Cache)
 Was ist der Programmzähler (Thread privat)?

Das PC-Register wird verwendet, um die Adresse zu speichern, die auf den nächsten Befehl verweist, den auszuführenden Befehlscode. Die nächste Anweisung wird von der Ausführungs-Engine gelesen.

  • Warum sind PC-Register auf „Thread Private“ eingestellt?

Multithreads führen nur eine der Thread-Methoden in einem bestimmten Zeitraum aus und die CPU wechselt ständig die Aufgaben, was unweigerlich zu häufigen Unterbrechungen oder Wiederherstellungen führt. Um die aktuelle Bytecode-Befehlsadresse, die von jedem Thread ausgeführt wird, genau aufzuzeichnen, wird jedem Thread ein PC-Register zugewiesen, und jeder Thread berechnet unabhängig, ohne sich gegenseitig zu beeinflussen.

 Was ist ein virtueller Maschinenstapel (Thread privat)?

Es ist für die Ausführung von Java-Programmen verantwortlich, speichert lokale Variablen und Teilergebnisse von Methoden und beteiligt sich am Aufruf und der Rückgabe von Methoden. Jeder Thread erstellt beim Erstellen einen Stapel einer virtuellen Maschine, in dem Stapelrahmen nacheinander gespeichert werden, was den Java-Methodenaufrufen nacheinander entspricht. Er ist für den Thread privat und hat denselben Lebenszyklus wie der Thread.

  • Merkmale?
  1. Der Stack ist eine schnelle und effiziente Möglichkeit, Speicher zuzuweisen, und seine Zugriffsgeschwindigkeit ist nach dem Programmzähler an zweiter Stelle.
  2. Die JVM hat nur zwei direkte Operationen auf dem Stapel der virtuellen Maschine: Jede Methode wird ausgeführt, begleitet vonPush (Push/Push), Die Ausführung der Methode wird beendetvom Stapel entfernt
  3. Es gibt kein Garbage-Collection-Problem auf dem Stapel
  4. Sie können den maximalen Stapelspeicherplatz des Threads über den Parameter festlegen-Xss. Die Größe des Stapels bestimmt direkt die maximal erreichbare Tiefe des Funktionsaufrufs
  • Welche Auffälligkeiten gibt es in diesem Bereich?
  1. Wenn ein Java Virtual Machine-Stack mit fester Größe verwendet wird, kann die Java Virtual Machine-Stackkapazität jedes Threads beim Erstellen des Threads unabhängig ausgewählt werden. Wenn der Thread die Zuweisung einer Stapelkapazität anfordert, die die vom Java Virtual Machine-Stapel maximal zulässige Kapazität überschreitet, löst die Java Virtual Machine eine StackOverflowError-Ausnahme< aus /span>
  2. Wenn der Stapel der virtuellen Java-Maschine dynamisch erweitert werden kann und beim Erweitern nicht genügend Speicher beantragen kann oder beim Erstellen eines neuen Threads nicht genügend Speicher zum Erstellen des entsprechenden Stapels der virtuellen Maschine vorhanden ist, wird die virtuelle Java-Maschine verwendet Maschine löst eineOutOfMemoryErrorAusnahme aus
  • Interne Struktur des Stapelrahmens?
  1. Lokale Variablen
  2. Operandenstapel (Operandenstapel) (oder Ausdrucksstapel)
  3. Dynamische Verknüpfung: Methodenreferenz, die auf den Laufzeitkonstantenpool verweist
  4. Methodenrückgabeadresse (Rückgabeadresse): Die Adresse, an der die Methode normal oder abnormal beendet wird
  5. einige zusätzliche Informationen
 Wie führt der Java Virtual Machine Stack Methodenberechnungen durch?

Nehmen Sie den folgenden Code als Beispiel:

private static int add(int a, int b) {
    int c = 0;
    c = a + b;
    return c;
}

Sie können Bytecode über Tools wie jsclass anzeigen

Die Schritte zum Schieben des Stapels sind wie folgt: Wenn der Wert 100+98 berechnet wird, sind die Änderungen im Operandenstapel wie folgt:

 Was ist der lokale Methodenstapel (thread privat)?
  • native Methodenschnittstelle

Eine native Methode ist eine Schnittstelle für Java zum Aufrufen von Nicht-Java-Code. Die uns bekannte Unsafe-Klasse verfügt über viele lokale Methoden.

  • Nativer Methodenstapel

Der Java Virtual Machine Stack wird zum Verwalten des Aufrufs von Java-Methoden verwendet, während der native Methodenstapel zum Verwalten des Aufrufs nativer Methoden verwendet wird.

Was ist Methodenbereich (Thread-Sharing)?

Der Methodenbereich ist nur ein Konzept, das inJVM-Spezifikation definiert ist und zum Speichern von Klasseninformationen, Konstantenpool, statischen Variablen und JIT-Kompilierung verwendet wird Code und andere Daten geben nicht an, wie es implementiert werden soll, und verschiedene Hersteller haben unterschiedliche Implementierungen. Und Permanent Generation (PermGen) ist ein Konzept, das nur für Hotspot virtuelle Maschinen gilt . In Java 8 wurde es durch metaspace ersetzt. Sowohl die permanente Generierung als auch der Metaspace können als Implementierung des Methodenbereichs verstanden werden.

Passen Sie die Größe des Methodenbereichs vor JDK1.8 an:

-XX:PermSize=N //方法区(永久代)初始大小
-XX:MaxPermSize=N //方法区(永久代)最大大小,超出这个值将会抛出OutOfMemoryError 

Ab JDK 1.8 wurde der Methodenbereich (die permanente Generierung von HotSpot) vollständig gelöscht und durch Metaspace ersetzt, der den lokalen Speicher direkt nutzt. Parametereinstellungen:

-XX:MetaspaceSize=N //设置Metaspace的初始(和最小大小)
-XX:MaxMetaspaceSize=N //设置Metaspace的最大大小

Interaktive Beziehung zwischen Stapel, Heap und Methodenbereich

Was sind die Unterschiede in der Speichernutzung zwischen permanenter Generierung und Metaspace?

Die Java Virtual Machine-Spezifikation definiert nur den Methodenbereich zum Speichern von Daten wie Klasseninformationen, Konstanten, statischen Variablen und Just-in-Time-kompiliertem Code, die von der virtuellen Maschine geladen wurden.

  1. Ab JDK1.7 werden Symbolreferenzen im nativen Heap gespeichert, und Zeichenfolgenkonstanten und statische Typvariablen werden im normalen Heap-Bereich gespeichert, die Trennung ist jedoch nicht vollständig. Zu diesem Zeitpunkt speichert die permanente Generation auch andere Metadaten, die vorhanden sind Hat nichts mit der Klasse zu tun. Verschiedenes
  2. Nach jdk8 werden die Metadaten der in der ursprünglichen permanenten Generation von HotSpot gespeicherten Klassen im Metaspace gespeichert und Statische Variablen und String-Konstanten der Klasse werden im Java-Heap platziert. Metaspace ist eine Implementierung des Methodenbereichs, nutzt jedoch nicht den Speicher in der virtuellen Maschine , sondern der lokale Speicher. Speicher. Die im Metaspace gespeicherten Daten sind viel reiner als die in der permanenten Generation. Es handelt sich lediglich um Metadaten der Klasse. Diese Informationen sind nur zur Kompilierungszeit oder zur JVM-Laufzeit nützlich.
  3. Die permanente Generation verfügt über eine JVM selbst mit einer festen Online-Größe und kann nicht angepasst werden, während der Metaspace direkten Speicher verwendet, der durch den verfügbaren Speicher der Maschine begrenzt ist und wird Habe nie java.lang.OutOfMemoryError erhalten.
  4. Die Symbolreferenz existiert nicht im Metaspace, sondern im nativen Heap. Dies sind zwei Methoden und Speicherorte, die jedoch beide als lokaler Speicher betrachtet werden können. Zwischen dem virtuellen Maschine Wenn kein begrenzender Parameter festgelegt ist, wird er nur durch die physische Speichergröße begrenzt. Das heißt, OOM tritt nur auf, wenn der verfügbare Speicher des Betriebssystems voll ist.
 Wie ist der Heap-Bereichsspeicher aufgeteilt?

Bei den meisten Anwendungen ist der Java-Heap der größte Speicherbereich, der von der Java Virtual Machine verwaltet wird und von allen Threads gemeinsam genutzt wird. Der einzige Zweck dieses Speicherbereichs besteht darin, Objektinstanzen zu speichern. Fast allen Objektinstanzen und Daten wird hier Speicher zugewiesen.

Um eine effiziente Speicherbereinigung durchzuführen, unterteilt die virtuelle Maschine den Heap-Speicher logisch in drei Bereiche (der einzige Grund für die Generierung ist die Optimierung). GC-Leistung):

  1. Neue Generation (junge Generation): Neue Objekte und Objekte, die ein bestimmtes Alter noch nicht erreicht haben, gehören zur neuen Generation
  2. Alte Generation (Ruhestandsbereich): Bei Objekten, die schon lange genutzt werden, sollte der Speicherplatz der alten Generation größer sein als der der jungen Generation.

Die Java Virtual Machine-Spezifikation legt fest, dass sich der Java-Heap in einem physisch diskontinuierlichen Speicherbereich befinden kann, solange er logisch kontinuierlich ist, wie Festplattenspeicher. Bei der Implementierung kann es entweder eine feste Größe oder eine Skalierbarkeit haben. Mainstream-VMs sind skalierbar (gesteuert durch -Xmx und -Xms). Wenn der Heap vorhanden ist, ist die Instanzzuweisung nicht der Fall abgeschlossen ist und der Heap nicht mehr erweitert werden kann, wird eine AusnahmeOutOfMemoryError ausgelöst.

  • Junge Generation

In der jungen Generation entstehen alle neuen Objekte. Wenn die junge Generation voll ist, wird die Speicherbereinigung durchgeführt. Diese Garbage Collection heißt Minor GC. Die jüngere Generation ist in drei Teile unterteilt – Eden (Eden Memory) und zwei Überlebensbereiche (Survivor Memory , aufgerufen von/bis oder s0/s1), das Standardverhältnis ist 8:1:1

  1. Die meisten neu erstellten Objekte befinden sich im Eden-Speicherraum
  2. Wenn der Eden-Raum mit Objekten gefüllt ist, führen SieMinor GC aus und verschieben Sie alle überlebenden Objekte in einen überlebenden Raum a>
  3. Minor GC überprüft Überlebensobjekte und verschiebt sie in einen anderen Überlebensraum. Ein Überlebensraum ist also jedes Mal leer
  4. Objekte, die mehrere GC-Zyklen überstehen, werden in die alte Generation verschoben. Typischerweise wird dies dadurch erreicht, dass für Objekte der jungen Generation eine Altersschwelle festgelegt wird, bevor sie für die Beförderung in die alte Generation in Frage kommen
  • Alte Generation

Der Speicher der alten Generation enthält Objekte, die nach vielen Runden kleiner GC noch am Leben sind. Normalerweise wird die Speicherbereinigung durchgeführt, wenn die alte Generation voll ist. Die Speicherbereinigung der alten Generation wird als Major GC bezeichnet und dauert normalerweise länger.

Große Objekte gehen direkt zur alten Generation (große Objekte sind Objekte, die viel zusammenhängenden Speicherplatz benötigen). Der Zweck besteht darin, eine große Anzahl von Speicherkopien zwischen dem Eden-Bereich und den beiden Survivor-Bereichen zu vermeiden.

 Wie ist der Lebenszyklus von Objekten im Heap in JVM?
  1. Im Heap des JVM-Speichermodells ist der Heap in die junge Generation und die alte Generation unterteilt.
    • Känozoikum und Fortschritt Eden Ward Sum Survivor Ward ,Survivor くゆう Von Survivor und Zu Survivor Komposition
  2. Wenn ein Objekt erstellt wird, wird das Objekt zuerst dem Eden-Bereich der neuen Generation zugewiesen.
    • Zu diesem Zeitpunkt definiert die JVM einen Objekt-Jungzähler(-XX:MaxTenuringThreshold)
  3. Wenn der Eden-Speicherplatz nicht ausreicht, führt die JVM eine Garbage Collection (Minor GC) der neuen Generation durch.
    • Die JVM überträgt die überlebenden Objekte an den Survivor und das Objektalter beträgt +1
    • Objekte erfahren in Survivor auch Minor GC. Jedes Mal, wenn sie Minor GC erfahren, beträgt das Objektalter +1
  4. Wenn die Anzahl der zugewiesenen Objekte überschreitet-XX:PetenureSizeThreshold, werden die Objekte direkt der alten Generation zugewiesen
Was ist der Objektzuweisungsprozess in JVM?

Das Zuweisen von Speicher für Objekte ist eine sehr strenge und komplexe Aufgabe. JVM-Designer müssen nicht nur überlegen, wie und wo Speicher zugewiesen werden soll, sondern auch die GC-Ausführung berücksichtigen, da der Speicherzuweisungsalgorithmus und der Speicherrecyclingalgorithmus eng miteinander verbunden sind. Ob Speicherfragmentierung auftritt werden im Speicherbereich generiert, nachdem das Speicherrecycling abgeschlossen ist.

  1. Das neue Objekt wird zunächst im Eden District platziert. Für diesen Bereich gelten Größenbeschränkungen.
  2. Wenn der Platz in Eden voll ist und das Programm Objekte erstellen muss, führt der Garbage Collector der JVM eine Garbage Collection (Minor GC) für Eden durch und zerstört Objekte in Eden, auf die nicht mehr von anderen Objekten verwiesen wird. Laden Sie dann neue Objekte und platzieren Sie sie im Eden Park
  3. Verschieben Sie dann die verbleibenden Objekte in Eden in die Überlebenszone 0
  4. Wenn die Müllsammlung erneut ausgelöst wird, werden die Elemente, die das letzte Mal überlebt haben, im Überlebensbereich 0 platziert. Wenn kein Recycling erfolgt, werden sie im Überlebensbereich 1 platziert.
  5. Wenn es die Garbage Collection erneut durchläuft, wird es wieder in die Survivor-Zone 0 und dann in die Survivor-Zone 1 verschoben.
  6. Wann werden Sie in eine Altersgemeinschaft gehen? Der Standardwert beträgt 15 Recyclingmarken
  7. Im Rentenbereich geht es relativ gemächlich zu. Wenn der Speicher im Ruhestandsbereich nicht ausreicht, wird der Major GC erneut ausgelöst, um den Speicher im Ruhestandsbereich zu bereinigen.
  8. Wenn festgestellt wird, dass das Objekt nach der Ausführung von Major GC im Ruhestandsbereich nicht gespeichert werden kann, tritt eine OOM-Ausnahme auf.
 Was ist TLAB (Thread Local Allocation Buffer)?
  • Aus Sicht des Speichermodells und nicht der Garbage Collection ist der Eden-Bereich weiterhin geteilt. Die JVM weist jedem Thread einen privaten Cache-Bereich zu, der im Eden-Bereich enthalten ist.
  • Wenn mehrere Threads gleichzeitig Speicher zuweisen, kann die Verwendung von TLAB eine Reihe von Nicht-Thread-Sicherheitsproblemen vermeiden und den Durchsatz der Speicherzuweisung verbessern. Daher können wir diese Speicherzuweisungsmethode aufrufen< a i =1>Schnelle Zuteilungsstrategie
  • Die meisten von OpenJDK abgeleiteten JVMs bieten TLAB-Design
 Warum TLAB?
  • Der Heap-Bereich wird von Threads gemeinsam genutzt, und jeder Thread kann auf die gemeinsam genutzten Daten im Heap-Bereich zugreifen.
  • Da in der JVM sehr häufig Objektinstanzen erstellt werden, ist es nicht threadsicher, den Speicherplatz in einer gleichzeitigen Umgebung vom Heap zu trennen.
  • Um zu verhindern, dass mehrere Threads dieselbe Adresse verwenden, müssen Sperrmechanismen und andere Mechanismen verwendet werden, die sich auf die Zuweisungsgeschwindigkeit auswirken.

Obwohl nicht alle Objektinstanzen erfolgreich Speicher in TLAB zuweisen können, verwendet die JVM TLAB als erste Wahl für die Speicherzuweisung.

Im Programm können Sie festlegen, ob TLAB-Speicherplatz durch -XX:UseTLAB aktiviert werden soll.

Standardmäßig ist der Speicher des TLAB-Speicherplatzes sehr klein und belegt nur 1 % des gesamten Eden-Speicherplatzes. Wir können den Prozentsatz des vom TLAB-Speicherplatz belegten Eden-Speicherplatzes über -XX:TLABWasteTargetPercent

Sobald es einem Objekt nicht gelingt, Speicher im TLAB-Bereich zuzuweisen, versucht die JVM, die Atomizität der Datenoperationen sicherzustellen, indem sie einen Sperrmechanismus verwendet, um Speicher direkt im Eden-Bereich zuzuweisen.

 5.3 GC-Garbage Collection

 Wie kann festgestellt werden, ob ein Gegenstand recycelt werden kann?
  • Referenzzählalgorithmus

Fügen Sie dem Objekt einen Referenzzähler hinzu. Wenn dem Objekt eine Referenz hinzugefügt wird, wird der Zähler um 1 erhöht, und wenn die Referenz ungültig wird, wird der Zähler um 1 dekrementiert. Objekte mit einem Referenzzähler von 0 können recycelt werden.

Wenn zwischen zwei Objekten ein Zirkelverweis besteht, ist der Referenzzähler niemals 0, was dazu führt, dass sie nicht recycelt werden können.

Aufgrund der Existenz von Zirkelverweisen verwendet die Java Virtual Machine keinen Referenzzählalgorithmus.

  • Algorithmus zur Erreichbarkeitsanalyse

Durch die Suche über GC Roots als Ausgangspunkt bleiben alle erreichbaren Objekte lebendig und nicht erreichbare Objekte können recycelt werden.

Die Java Virtual Machine verwendet diesen Algorithmus, um zu bestimmen, ob ein Objekt recycelt werden kann. In Java umfassen GC Roots im Allgemeinen Folgendes:

  • Objekte, auf die im Stapel der virtuellen Maschine verwiesen wird
  • Objekt, auf das im lokalen Methodenstapel verwiesen wird
  • Das Objekt, auf das die statische Klasseneigenschaft im Methodenbereich verweist
  • Das Objekt, auf das die Konstante im Methodenbereich verweist
 Was sind die Referenztypen von Objekten?

Unabhängig davon, ob es darum geht, die Anzahl der Verweise auf ein Objekt mithilfe eines Referenzberechnungsalgorithmus zu bestimmen oder ob ein Objekt mithilfe eines Erreichbarkeitsanalysealgorithmus erreichbar ist, hängt die Bestimmung, ob ein Objekt recycelt werden kann, mit Referenzen zusammen.

Java verfügt über vier Referenztypen mit unterschiedlichen Stärken.

  • starke Referenz

Mit starken Referenzen verknüpfte Objekte werden nicht recycelt.

Verwenden Sie new, um ein neues Objekt zu erstellen und eine starke Referenz zu erstellen.

Object obj = new Object();
  • weiche Referenz

Mit Soft-Referenzen verknüpfte Objekte werden nur recycelt, wenn nicht genügend Speicher vorhanden ist.

Verwenden Sie die SoftReference-Klasse, um Soft-Referenzen zu erstellen.

Object obj = new Object();
SoftReference<Object> sf = new SoftReference<Object>(obj);
obj = null;  // 使对象只被软引用关联
  • schwaches Zitat

Das mit einer schwachen Referenz verknüpfte Objekt wird definitiv recycelt, was bedeutet, dass es nur bis zur nächsten Speicherbereinigung überleben kann.

Verwenden Sie die Klasse WeakReference, um schwache Referenzen zu implementieren.

Object obj = new Object();
WeakReference<Object> wf = new WeakReference<Object>(obj);
obj = null;
  • virtuelle Referenz

Auch Geisterzitate oder Phantomzitate genannt. Ob ein Objekt über eine virtuelle Referenz verfügt, hat keinen Einfluss auf seine Überlebenszeit, und ein Objekt kann nicht über eine virtuelle Referenz abgerufen werden.

Der einzige Zweck des Festlegens einer virtuellen Referenzzuordnung für ein Objekt besteht darin, eine Systembenachrichtigung zu erhalten, wenn das Objekt recycelt wird.

Verwenden Sie PhantomReference, um virtuelle Referenzen zu implementieren.

Object obj = new Object();
PhantomReference<Object> pf = new PhantomReference<Object>(obj);
obj = null;
 Was sind die grundlegenden Garbage-Collection-Algorithmen?
  • Mark – Klar

Markieren Sie die verbleibenden Objekte und bereinigen Sie dann die nicht markierten Objekte.

unzureichend:

  • Sowohl die Markierungs- als auch die Löschprozesse sind ineffizient;
  • Es wird eine große Anzahl diskontinuierlicher Speicherfragmente generiert, was dazu führt, dass großer Objekte kein Speicher zugewiesen werden kann.
  • Tag – Organisieren

Lassen Sie alle lebenden Objekte zu einem Ende wandern und bereinigen Sie dann direkt den Speicher außerhalb der Endgrenze.

  • Kopieren

Teilen Sie den Speicher in zwei Blöcke gleicher Größe auf und verwenden Sie jeweils nur einen davon. Wenn dieser Speicherblock aufgebraucht ist, kopieren Sie die verbleibenden Objekte in den anderen Block und bereinigen Sie dann den verwendeten Speicherplatz.

Der Hauptnachteil besteht darin, dass nur die Hälfte des Speichers genutzt wird.

Heutige kommerzielle virtuelle Maschinen verwenden alle diesen Sammelalgorithmus, um die neue Generation zu recyceln. Die neue Generation ist jedoch nicht in zwei gleich große Teile unterteilt, sondern in einen größeren Eden-Raum und zwei kleinere Survivor-Räume. Jeder nutzt den Eden Weltraum und einer der Überlebenden zum ersten Mal. Kopieren Sie während des Recyclings die überlebenden Objekte in Eden und Survivor gleichzeitig in einen anderen Survivor-Bereich und räumen Sie schließlich Eden und den verwendeten Survivor auf.

Das Standardgrößenverhältnis von Eden und Survivor der virtuellen HotSpot-Maschine beträgt 8:1, wodurch sichergestellt wird, dass die Speicherauslastung 90 % erreicht. Wenn mehr als 10 % der Objekte jedes Recycling überstehen, reicht ein Stück Survivor-Speicherplatz nicht aus. Zu diesem Zeitpunkt müssen Sie sich bei der Zuteilungsgarantie auf die alte Generation verlassen, dh den Speicherplatz der alten Generation zum Speichern ausleihen Gegenstände, die nicht untergebracht werden können.

  • Sammlung nach Generation

Heutige kommerzielle virtuelle Maschinen verwenden einen Generationen-Sammelalgorithmus, der den Speicher entsprechend dem Überlebenszyklus des Objekts in mehrere Blöcke aufteilt und geeignete Sammelalgorithmen für verschiedene Blöcke verwendet.

Der Heap ist im Allgemeinen in die neue Generation und die alte Generation unterteilt.

  • Verwendung der neuen Generation: Replikationsalgorithmus
  • Verwendung der alten Generation: Mark-Clear- oder Mark-Collate-Algorithmus
 Was ist der Unterschied zwischen dem Generationssammlungsalgorithmus und dem Partitionssammlungsalgorithmus?
  • Algorithmus zur Generationensammlung

Die aktuelle Mainstream-VM-Garbage Collection verwendet den Algorithmus „Generational Collection“. Dieser Algorithmus unterteilt den Speicher in mehrere Blöcke entsprechend den unterschiedlichen Lebenszyklen von Objekten, z. B. der neuen Generation, der alten Generation und der permanenten Generation in der JVM. Auf diese Weise Am meisten Entsprechend den Merkmalen jeder Epoche kann ein geeigneter GC-Algorithmus verwendet werden.

In der jungen Generation - Replikationsalgorithmus:

Bei jeder Speicherbereinigung kann festgestellt werden, dass eine große Anzahl von Objekten tot ist und nur wenige am Leben sind. Daher kann die Sammlung mithilfe des Kopieralgorithmus mit nur geringen Kopierkosten für überlebende Objekte abgeschlossen werden.

In der alten Generation - Markierungskollationsalgorithmus:

Da das Objekt eine hohe Überlebensrate aufweist und kein zusätzlicher Speicherplatz zugewiesen wird, um dies zu gewährleisten, muss zum Recycling der Algorithmus „Mark-Clean“ oder „Mark-Organize“ verwendet werden, ohne dass der Speicher kopiert werden muss, und freier Speicher kann direkt freigegeben werden.

  1. ParNew: Ein Multithread-Kollektor, der einen Kopieralgorithmus verwendet und hauptsächlich im Young-Bereich arbeitet. Die Sammlung kann über -XX:ParallelGCThreads gesteuert werden Parameter Die Anzahl der Threads, der gesamte Prozess ist STW und wird häufig in Kombination mit CMS verwendet.

  2. CMS: Mit dem Ziel, die kürzeste Recycling-Pausezeit zu erreichen, wird der „Mark-Clear“-Algorithmus verwendet, um die Speicherbereinigung in 4 Schritten durchzuführen, wobei die anfängliche Markierung und erneute -Markierung wird STW. Die meisten davon werden auf der Serverseite von Internet-Websites oder B/S-Systemen verwendet. JDK9 wird als veraltet markiert und JDK14 wird gelöscht.

  • Algorithmus zur Partitionssammlung

Der Partitionsalgorithmus unterteilt den gesamten Heap-Speicherplatz in verschiedene kontinuierliche kleine Intervalle, und jedes kleine Intervall wird unabhängig verwendet und unabhängig recycelt. Der Vorteil davon besteht darin, dass gesteuert werden kann, wie viele kleine Intervalle gleichzeitig recycelt werden, und zwar entsprechend der Zielpause Zeit kann jedes Mal eine angemessene Anzahl kleiner Intervalle recycelt werden. Ein kleines Intervall (anstelle des gesamten Heaps), wodurch die durch einen GC verursachten Pausen reduziert werden.

  1. G1: Ein serverseitiger Garbage Collector, der in Umgebungen mit mehreren Prozessoren und großer Speicherkapazität verwendet wird, um einen hohen Durchsatz zu erreichen und gleichzeitig die Garbage Collection so weit wie möglich zu erfüllen. Timeout-Anforderungen .

  2. ZGC: Ein in JDK11 eingeführter Garbage Collector mit geringer Latenz, der für die Speicherverwaltung und das Recycling von Diensten mit großem Speicher und geringer Latenz geeignet ist. SPECjbb 2015 Benchmark-Test, in 128G großem Speicher Unter Im Heap beträgt die maximale Pausenzeit nur 1,68 ms, was viel besser ist als bei G1 und CMS.

 Was sind Minor GC, Major GC und Full GC?

Wenn die JVM eine GC durchführt, werden die Heap-Speicherbereiche (neue Generation, alte Generation; Methodenbereich) nicht jedes Mal gemeinsam recycelt. In den meisten Fällen wird die neue Generation recycelt.

Für die Implementierung von HotSpot VM wird der darin enthaltene GC je nach Recyclingbereich in zwei Kategorien unterteilt: Teilsammlung (Partial GC) und vollständige Heap-Sammlung (Full GC).

  • Teilweise Sammlung: Eine Garbage Collection, die nicht den gesamten Java-Heap vollständig sammelt. Was weiter unterteilt ist in:
    • Sammlung der neuen Generation (Minor GC/Young GC): Nur Garbage Collection der neuen Generation
    • Sammlung der alten Generation (Major GC/Old GC): Nur Müllsammlung in der alten Generation
      • Derzeit verfügt nur CMS GC über das Verhalten, die alte Generation separat zu sammeln.
      • In vielen Fällen wird Major GC mit Full GC gemischt. Es muss zwischen der Sammlung alter Generationen und der vollständigen Heap-Sammlung unterschieden werden.
    • Gemischter GC: Sammeln Sie den Müll der gesamten neuen Generation und eines Teils der alten Generation
      • Derzeit weist nur G1 GC dieses Verhalten auf
  • Vollständige Heap-Sammlung (vollständiger GC): Sammeln Sie Müll im gesamten Java-Heap- und Methodenbereich
 Sprechen Sie über die JVM-Speicherzuweisungsstrategie?
  • Objekte werden zuerst in Eden zugewiesen

In den meisten Fällen werden Objekte im Eden-Bereich der neuen Generation zugewiesen. Wenn der Eden-Bereich nicht ausreicht, wird Minor GC initiiert.

  • Große Objekte gelangen direkt in die alte Generation

Große Objekte beziehen sich auf Objekte, die kontinuierlichen Speicherplatz benötigen. Die typischsten großen Objekte sind sehr lange Zeichenfolgen und Arrays.

Große Objekte lösen die Garbage Collection häufig frühzeitig aus, um genügend zusammenhängenden Platz für die Zuweisung großer Objekte zu erhalten.

-XX:PretenureSizeThreshold: Objekte, die größer als dieser Wert sind, werden direkt in der alten Generation zugewiesen, um das Kopieren großer Speichermengen zwischen dem Eden-Bereich und dem Survivor-Bereich zu vermeiden.

  • Langlebige Gegenstände kommen ins Alter

Definieren Sie einen Alterszähler für das Objekt. Wenn das Objekt in Eden geboren wird und den Minor GC noch überlebt, wird es in den Survivor verschoben und sein Alter wird um 1 Jahr erhöht. Wenn es ein bestimmtes Alter erreicht, wird dies der Fall sein zur alten Generation gewechselt.

-XX:MaxTenuringThreshold wird verwendet, um die Altersschwelle zu definieren.

  • Dynamische Bestimmung des Objektalters

Die virtuelle Maschine erfordert nicht immer, dass das Alter des Objekts MaxTenuringThreshold erreichen muss, bevor es auf die alte Generation hochgestuft werden kann. Wenn die Summe der Größen aller gleichaltrigen Objekte im Survivor größer als die Hälfte des Survivor-Speicherplatzes ist Objekte, deren Alter größer oder gleich diesem Alter ist, können direkt in die alte Generation eintreten. Es besteht keine Notwendigkeit, bis zum erforderlichen Alter in MaxTenuringThreshold zu warten.

  • Platzzuteilungsgarantie

Bevor Minor GC auftritt, prüft die virtuelle Maschine zunächst, ob der maximal verfügbare kontinuierliche Speicherplatz in der alten Generation größer ist als der Gesamtspeicherplatz aller Objekte in der neuen Generation. Wenn die Bedingung wahr ist, kann Minor GC als sicher bestätigt werden.

Wenn nicht, prüft die virtuelle Maschine, ob der Einstellungswert von HandlePromotionFailure einen Garantiefehler zulässt. Wenn dies zulässig ist, prüft sie weiterhin, ob der maximal verfügbare kontinuierliche Speicherplatz in der alten Generation größer ist als die durchschnittliche Größe der zur alten Generation heraufgestuften Objekte . Wenn der Wert größer ist, wird versucht, einen Minor GC durchzuführen. ; Wenn er kleiner ist oder die HandlePromotionFailure-Einstellung das Eingehen von Risiken nicht zulässt, wird ein vollständiger GC durchgeführt.

 Unter welchen Umständen wird die vollständige GC ausgelöst?

Für Minor GC ist die Auslösebedingung sehr einfach: Wenn der Eden-Raum voll ist, wird ein Minor GC ausgelöst. Vollständige GC ist relativ komplex und weist die folgenden Bedingungen auf:

  • Rufen Sie System.gc() auf

Es wird nur empfohlen, dass die virtuelle Maschine Full GC ausführt, die virtuelle Maschine führt dies jedoch möglicherweise nicht tatsächlich aus. Es wird nicht empfohlen, diese Methode zu verwenden. Lassen Sie stattdessen die virtuelle Maschine den Speicher verwalten.

  • Zu wenig Platz in der alten Generation

Häufige Szenarien, in denen in der alten Generation nicht genügend Platz vorhanden ist, umfassen große Objekte, die wie oben erwähnt direkt in die alte Generation gelangen, langfristig überlebende Objekte, die in die alte Generation gelangen usw.

Um eine vollständige GC aus den oben genannten Gründen zu vermeiden, sollten Sie versuchen, keine zu großen Objekte und Arrays zu erstellen. Darüber hinaus können Sie den Parameter der virtuellen Maschine -Xmn verwenden, um die Größe der neuen Generation zu erhöhen, sodass Objekte in der neuen Generation recycelt werden können und nicht in die alte Generation gelangen. Sie können auch -XX:MaxTenuringThreshold verwenden, um das Alter zu erhöhen, in dem ein Objekt in die alte Generation eintritt, sodass das Objekt länger in der neuen Generation überleben kann.

  • Die Platzzuweisungsgarantie ist fehlgeschlagen

Minor GC unter Verwendung des Kopieralgorithmus benötigt zur Garantie den Speicherplatz der alten Generation. Wenn die Garantie fehlschlägt, wird eine vollständige GC ausgeführt.

  • Unzureichender Speicherplatz für die permanente Generierung in JDK 1.7 und früher

In JDK 1.7 und früher wird der Methodenbereich in der virtuellen HotSpot-Maschine mithilfe der permanenten Generierung implementiert, in der einige Klasseninformationen, Konstanten, statische Variablen und andere Daten gespeichert werden.

Wenn im System viele zu ladende Klassen, reflektierte Klassen und aufzurufende Methoden vorhanden sind, ist die permanente Generierung möglicherweise vollständig und die vollständige GC wird auch dann ausgeführt, wenn CMS GC nicht konfiguriert ist. Wenn es nach der vollständigen GC immer noch nicht recycelt werden kann, löst die virtuelle Maschine einen java.lang.OutOfMemoryError aus.

Um die aus den oben genannten Gründen verursachte vollständige GC zu vermeiden, können folgende Methoden angewendet werden: Erhöhen Sie den permanenten Generierungsraum oder wechseln Sie zur Verwendung von CMS GC.

  • Fehler im gleichzeitigen Modus

Wenn während der Ausführung von CMS GC gleichzeitig Objekte in die alte Generation eingefügt werden sollen und zu diesem Zeitpunkt nicht genügend Speicherplatz in der alten Generation vorhanden ist (kann es sein, dass während des GC-Prozesses zu viel schwebender Müll vorhanden ist). , was zu vorübergehendem Speicherplatzmangel führt), wird ein Concurrent Mode Failure-Fehler gemeldet und ausgelöst. Vollständiger GC.

 Welche Garbage Collectors gibt es in Hotspot?
  • Single-Threaded vs. Multi-Threaded: Single-Threaded bedeutet, dass der Garbage Collector nur einen Thread für die Sammlung verwendet, während Multithreaded mehrere Threads verwendet.
  • Seriell und parallel: Seriell bedeutet, dass der Garbage Collector und das Benutzerprogramm abwechselnd ausgeführt werden, was bedeutet, dass das Benutzerprogramm angehalten werden muss, wenn die Garbage Collection durchgeführt wird. Parallel bedeutet, dass der Garbage Collector und das Benutzerprogramm gleichzeitig ausgeführt werden . Mit Ausnahme von CMS und G1 werden andere Garbage Collectors seriell ausgeführt.
  1. Seriensammler

„Serial“ bedeutet „seriell“, was bedeutet, dass es seriell ausgeführt wird.

Es handelt sich um einen Single-Threaded-Collector, der nur einen Thread für die Garbage Collection verwendet.

Sein Vorteil besteht darin, dass es einfach und effizient ist. Da in einer Umgebung mit einer einzelnen CPU kein Overhead für die Thread-Interaktion anfällt, weist es die höchste Effizienz bei der Sammlung einzelner Threads auf.

Dies ist der Standardkollektor der neuen Generation im Client-Modus, da im Desktop-Anwendungsszenario des Benutzers der für die Verwaltung virtueller Maschinen zugewiesene Speicher im Allgemeinen nicht sehr groß ist. Der serielle Kollektor sammelt Dutzende Megabyte oder sogar ein oder zweihundert Megabyte Pausenzeit der neuen Generation, die innerhalb von mehr als hundert Millisekunden gesteuert werden kann. Solange sie nicht zu häufig ist, ist diese Pause akzeptabel.

  1. ParNew Collector

Es handelt sich um eine Multithread-Version des Serial Collectors.

Es ist der bevorzugte Kollektor der neuen Generation für virtuelle Maschinen im Servermodus. Neben Leistungsgründen liegt dies vor allem daran, dass er neben dem seriellen Kollektor der einzige ist, der mit dem CMS-Kollektor zusammenarbeiten kann.

Die Anzahl der standardmäßig aktivierten Threads entspricht der Anzahl der CPUs. Sie können den Parameter -XX:ParallelGCThreads verwenden, um die Anzahl der Threads festzulegen.

  1. Paralleler Scavenge-Kollektor

Wie ParNew ist es ein Multithread-Kollektor.

Andere Collectors konzentrieren sich auf die Minimierung der Pausenzeit von Benutzer-Threads während der Garbage Collection und ihr Ziel besteht darin, einen kontrollierbaren Durchsatz zu erreichen. Dies wird als „Throughput-First“-Collector bezeichnet. Der Durchsatz bezieht sich hier auf das Verhältnis der Zeit, die die CPU mit der Ausführung von Benutzercode verbringt, zur Gesamtzeit.

Je kürzer die Pausenzeit, desto besser eignet sie sich für Programme, die mit Benutzern interagieren müssen. Eine gute Reaktionsgeschwindigkeit kann die Benutzererfahrung verbessern. Ein hoher Durchsatz kann die CPU-Zeit effizient nutzen und die Rechenaufgaben des Programms so schnell wie möglich abschließen. Er eignet sich hauptsächlich für Aufgaben, die im Hintergrund ausgeführt werden und nicht zu viel Interaktion erfordern.

Die Verkürzung der Pausenzeit geht zu Lasten des Durchsatzes und des Speicherplatzes der neuen Generation: Der Speicherplatz der neuen Generation wird kleiner und die Speicherbereinigung wird häufiger, was zu einer Verringerung des Durchsatzes führt.

Die adaptive GC-Anpassungsstrategie (GC-Ergonomie) kann über einen Schalterparameter aktiviert werden, sodass keine detaillierten Parameter wie die Größe der neuen Generation (-Xmn), das Verhältnis der Eden- und Survivor-Bereiche usw. manuell angegeben werden müssen Das Zeitalter der Objekte wurde in die alte Generation befördert. Die virtuelle Maschine sammelt Informationen zur Leistungsüberwachung basierend auf den aktuellen Betriebsbedingungen des Systems und passt diese Parameter dynamisch an, um die am besten geeignete Pausenzeit oder den maximalen Durchsatz bereitzustellen.

  1. Serien-Altsammler

Es handelt sich um die Version des Serial Collectors der alten Generation und wird auch von virtuellen Maschinen im Client-Modus verwendet. Wenn es im Servermodus verwendet wird, hat es zwei Hauptverwendungszwecke:

  • Wird mit dem Parallel Scavenge-Kollektor in JDK 1.5 und früher (bevor Parallel Old geboren wurde) verwendet.
  • Als Backup-Plan für den CMS-Collector wird er verwendet, wenn bei der gleichzeitigen Sammlung ein Fehler im gleichzeitigen Modus auftritt.
  1. Paralleler alter Sammler

Ist die Version der alten Generation des Parallel Scavenge-Kollektors.

In Situationen, in denen der Durchsatz wichtig und die CPU-Ressourcen empfindlich sind, kann Parallel Scavenge plus Parallel Old Collector Vorrang erhalten.

  1. CMS-Kollektor

CMS (Concurrent Mark Sweep), Mark Sweep bezieht sich auf den Mark-Sweep-Algorithmus.

Es ist in die folgenden vier Prozesse unterteilt:

  • Anfängliche Markierung: Markiert lediglich Objekte, mit denen GC Roots direkt in Verbindung stehen kann. Dies geht sehr schnell und erfordert eine Pause.
  • Gleichzeitige Markierung: Der Prozess der GC Roots Tracing, der im gesamten Recyclingprozess die längste Zeit in Anspruch nimmt und keine Pausen erfordert.
  • Anmerkung: Um den Markierungsdatensatz des Teils des Objekts zu korrigieren, der sich aufgrund der fortgesetzten Ausführung des Benutzerprogramms während der gleichzeitigen Markierung geändert hat, ist eine Pause erforderlich.
  • Gleichzeitige Bereinigung: keine Pausen erforderlich.

Während der gleichzeitigen Markierungs- und gleichzeitigen Reinigungsprozesse, die im gesamten Prozess am längsten sind, kann der Kollektor-Thread ohne Pause mit dem Benutzer-Thread zusammenarbeiten.

Hat folgende Nachteile:

  • Geringer Durchsatz: Geringe Pausenzeiten gehen zu Lasten des Durchsatzes und führen zu einer unzureichenden CPU-Auslastung.
  • Floating Garbage kann nicht verarbeitet werden, es kann zu einem Concurrent Mode Failure kommen. Floating-Müll bezieht sich auf den Müll, der von Benutzer-Threads erzeugt wird, die während der gleichzeitigen Bereinigungsphase weiter ausgeführt werden. Dieser Teil des Mülls kann nur beim nächsten GC recycelt werden. Aufgrund des Vorhandenseins von schwebendem Müll muss ein Teil des Speichers reserviert werden, was bedeutet, dass die CMS-Sammlung nicht wie andere Sammler warten kann, bis die alte Generation fast voll ist, bevor sie recycelt wird. Wenn der reservierte Speicher nicht ausreicht, um schwebenden Müll zu speichern, tritt ein Fehler im gleichzeitigen Modus auf und die virtuelle Maschine aktiviert vorübergehend Serial Old, um CMS zu ersetzen.
  • Die durch den Mark-and-Clear-Algorithmus verursachte Speicherplatzfragmentierung führt häufig dazu, dass in der alten Generation Speicherplatz verbleibt. Dieser kann jedoch keinen ausreichend großen kontinuierlichen Speicherplatz für die Zuweisung des aktuellen Objekts finden und muss im Voraus eine vollständige GC auslösen.
  1. G1-Sammler

G1 (Garbage-First), ein Garbage Collector für serverseitige Anwendungen, bietet eine gute Leistung in Szenarien mit mehreren CPUs und großem Speicher. Das HotSpot-Entwicklungsteam hat es sich zur Aufgabe gemacht, den CMS-Kollektor in Zukunft zu ersetzen.

Der Heap ist in die neue Generation und die alte Generation unterteilt. Der Sammelbereich anderer Sammler ist die gesamte neue Generation oder die alte Generation, währendG1 die neue direkt sammeln kann Generation und die alte Generation. Gemeinsam recyceln.

G1 unterteilt den Heap in mehrere unabhängige Regionen (Regionen) gleicher Größe, und die neue Generation und die alte Generation sind nicht mehr physisch isoliert.

Durch die Einführung des Regionskonzepts wird der ursprüngliche gesamte Speicherraum in mehrere kleine Räume unterteilt, sodass jeder kleine Raum unabhängig voneinander durch Müll gesammelt werden kann. Diese Partitionierungsmethode bietet viel Flexibilität und ermöglicht vorhersehbare Pausenzeitmodelle. Durch Aufzeichnen der Müllabfuhrzeit jeder Region und des durch Recycling gewonnenen Platzes (diese beiden Werte werden durch frühere Recyclingerfahrungen ermittelt) und durch Führen einer Prioritätenliste, jedes Mal basierend auf der zulässigen Sammlungszeit, wird die Region mit der Der größte Wert wird zuerst recycelt.

Jede Region verfügt über einen gespeicherten Satz, der zum Aufzeichnen der Region verwendet wird, in der sich das Referenzobjekt des Regionsobjekts befindet. Durch die Verwendung von Remembered Set können Sie bei der Erreichbarkeitsanalyse einen vollständigen Heap-Scan vermeiden.

Wenn Sie den Vorgang der Aufrechterhaltung des gespeicherten Satzes nicht mitzählen, kann der Vorgang des G1-Kollektors grob in die folgenden Schritte unterteilt werden:

  • Anfangsnote
  • gleichzeitige Markierung
  • Endgültige Markierung: Um den Teil des Markierungsdatensatzes zu korrigieren, der sich aufgrund des fortgesetzten Betriebs des Benutzerprogramms während der gleichzeitigen Markierung ändert, zeichnet die virtuelle Maschine die Objektänderungen während dieses Zeitraums in den gespeicherten Satzprotokollen des Threads auf. Die letzte Markierungsphase ist erforderlich um sich die Satzprotokolle zu merken. Die Daten werden im gespeicherten Satz zusammengeführt. Für diese Phase muss der Thread angehalten werden, sie kann jedoch parallel ausgeführt werden.
  • Screening und Recycling: Sortieren Sie zunächst den Recyclingwert und die Recyclingkosten in jeder Region und formulieren Sie einen Recyclingplan basierend auf der vom Benutzer erwarteten GC-Pausenzeit. Tatsächlich kann diese Phase auch gleichzeitig mit dem Benutzerprogramm ausgeführt werden. Da jedoch nur ein Teil der Region recycelt wird, kann die Zeit vom Benutzer gesteuert werden, und das Anhalten des Benutzerthreads verbessert die Erfassungseffizienz erheblich.

Es weist folgende Eigenschaften auf:

  • Räumliche Integration: Insgesamt handelt es sich um einen Kollektor, der auf dem „Mark-Sort“-Algorithmus basiert. Aus lokaler Sicht (zwei R
  • zwischen Regionen) wird auf Basis des „Kopieren“-Algorithmus implementiert, was bedeutet, dass im Betrieb keine Speicherplatzfragmentierung erzeugt wird.
  • Vorhersehbare Pausen: Ermöglicht dem Benutzer die explizite Angabe, dass die für GC aufgewendete Zeit N Millisekunden innerhalb eines Zeitsegments mit einer Länge von M Millisekunden nicht überschreiten darf.

Guess you like

Origin blog.csdn.net/abclyq/article/details/134842504