Java-Leistung Kapitel 5 Grundlagen der Garbage Collection

O'Reilly Japan \ -Java Performance Zusammenfassung von Kapitel 5 dieses Buches

Kapitel 1 Einführung \ -Qiita Kapitel 2 Ansatz für Leistungstests \ -Qiita Kapitel 3 Java Performance Toolbox \ -Qiita Kapitel 4 Mechanismus des JIT-Compilers \ -Qiita ← Vorheriger Artikel

5.1 Übersicht über die Speicherbereinigung

Der Reiz von Java besteht darin, dass Entwickler den Lebenszyklus von Objekten nicht kennen müssen. Dies kann jedoch eine Schwäche bei der Optimierung der Speichernutzung sein. Nach den Erfahrungen des Autors dieses Buches ist die Zeit, die für die Arbeit am Java-Speicher aufgewendet wird, kürzer als die Zeit, die für die Beseitigung von Fehlern im Zusammenhang mit baumelnden Zeigern und Nullzeigern in anderen Sprachen aufgewendet wird.

Wenn von nirgendwo darauf verwiesen wird, unterliegt es der GC. Wenn es jedoch eine Liste mit einer Struktur gibt, in der ein Element auf das nächste Element verweist, z. B. eine verkettete Liste, und die Liste selbst nicht darauf verweist, kann die gesamte Liste freigegeben werden.

Der Heap wird regelmäßig nach nicht verwendeten Objekten durchsucht. Sie müssen Speicherbereiche irgendwo kombinieren, um eine Speicherfragmentierung zu verhindern.

Die Leistung der Speicherbereinigung wird durch die folgenden drei bestimmt.

Beim Nachschlagen von Objektreferenzen oder Verschieben von Objekten im Speicher muss der Anwendungsthread diese Objekte unbenutzt lassen. Das Stoppen eines Anwendungsthreads wird als Stop-the-World-Pause bezeichnet.

Generationsbasierter Garbage Collector

Der Heap-Bereich ist in die folgenden Bereiche unterteilt.

Der Grund, warum es in mehrere Teile unterteilt ist, ist, dass die meisten Objekte nur für einen kurzen Zeitraum verwendet werden.

Das Objekt wird zuerst Eden im jungen Bereich zugewiesen.

Bei kleineren Garbage Collections stoppt der Garbage Collector, wenn dieser Bereich voll ist, alle Anwendungsthreads, verschiebt gebrauchte Objekte in einen anderen Bereich und leert den jungen Bereich (nicht verwendete Objekte verschwinden). ).

Diese Methode bietet zwei Vorteile:

Das wiederholte Bewegen in den alten Bereich füllt den alten Bereich. Die Verarbeitung des alten Bereichs hängt vom Garbage Collection-Algorithmus ab.

Der Prozess ist kompliziert, aber CMS und G1 können nach nicht verwendeten Objekten suchen, ohne den Anwendungsthread anzuhalten. Es verbraucht jedoch mehr CPU-Zyklen. Diese Speicherbereinigungen können auch vollständige Speicherbereinigungen sein. Eines der Hauptziele bei der Optimierung gleichzeitiger Speicherbereinigungen besteht darin, vollständige Speicherbereinigungen zu vermeiden.

Richtlinien, für die der Garbage Collector verwendet werden soll

Wenn die Reaktionszeit wichtig ist Das Stoppen von Threads (insbesondere der vollständigen Speicherbereinigung) hat einige Auswirkungen auf Anforderungen. Wenn Sie dies jedoch unterdrücken möchten, erfolgt die gleichzeitige Speicherbereinigung Wenn die durchschnittliche Reaktionszeit wichtig ist, dann der Durchsatz-Garagensammler

Wenn es sich um einen Stapelverarbeitungstyp handelt Garbage Collection vom gleichzeitigen Typ, wenn CPU-Ressourcen verfügbar sind. Sie können die Unterbrechung aufgrund der vollständigen Speicherbereinigung vermeiden und den Vorgang schnell abschließen. Wenn die CPU-Ressourcen begrenzt sind, wird es noch langsamer.

Garbage Collection-Algorithmus

Es gibt vier

1. Serieller Müllsammler

Das einfachste. Es gibt nur einen Thread, der den Heap verarbeitet. Stoppen Sie den Anwendungsthread sowohl für die kleinen als auch für die vollständigen Speicherbereinigungen. Kann mit -XX: + UseSerialGC aktiviert werden.

2. Im gesamten Müllsammler

Eine geringfügige Speicherbereinigung ist schneller als eine serielle Speicherbereinigung, da mehrere Threads zum Verarbeiten des jungen Bereichs verwendet werden. Aktivieren -XX:+UseParallelGC -XX: + UseParallelOldGC (Verwenden Sie mehrere Threads, um den alten Bereich zu verarbeiten.) Und.

3. CMS Garbage Collector

CMS (Concurrent Mark Sweep) wurde entwickelt, um lange Ausfälle im Zusammenhang mit der vollständigen Speicherbereinigung zu vermeiden. Anwendungsthreads werden nur während einer geringfügigen Speicherbereinigung gestoppt. Stattdessen werden CPU-Ressourcen verbraucht. Hintergrund-Threads werden nicht komprimiert, sodass der Heap fragmentiert bleibt. Wenn nicht genügend CPU-Ressourcen vorhanden sind oder wenn die Heap-Fragmentierung fortschreitet und keine Objekte zugewiesen werden können, wird der gleiche Vorgang wie beim seriellen Typ ausgeführt. Aktivieren -XX:+UseConcMarkSweepGC -XX:+UseParNewGC Und.

4. G1 Garbage Collector

G1 (Garbage 1st) zielt darauf ab, einen großen Heap (4 GB oder mehr) mit einer minimalen Ausfallzeit zu verarbeiten. Der Heap ist zur Verarbeitung in mehrere Regionen unterteilt. Kopieren Sie Objekte, die in einer Region verwendet werden, in eine andere Region. Dann ist die Theorie, dass es automatisch (teilweise) verdichtet wird. Wie CMS wird die vollständige Speicherbereinigung vermieden, sodass viele CPU-Ressourcen verbraucht werden. Aktivieren -XX:+UseG1GC Und.

Erzwungene Ausführung und Deaktivierung der Speicherbereinigung

Eine geringfügige Speicherbereinigung erfolgt, wenn der junge Bereich voll ist. Die vollständige Speicherbereinigung erfolgt, wenn der alte Bereich voll ist. Die gleichzeitige Speicherbereinigung erfolgt, wenn der Heap gefüllt werden soll.

Es ist wenig sinnvoll, eine Speicherbereinigung mit "System.gc ()" zu erzwingen. Die vollständige Speicherbereinigung wird immer durchgeführt, auch wenn die Speicherbereinigung nach CMS oder G1 verwendet wird. Nur das Verschieben der Speicherbereinigung, die vorzeitig erfolgt, verbessert die Leistung nicht. Es ist jedoch sinnvoll, wenn es um Leistungsüberwachung und Benchmark-Messungen geht. Es ist möglich, vor der Messung eine Speicherbereinigung durchzuführen und die Messung in einem sauberen Zustand durchzuführen. Die Gavage-Sammlung vor der Ausgabe des Heap-Dumps hat auch den Vorteil, dass die Analyse des Heaps vereinfacht wird (obwohl in den meisten Fällen die meisten Heap-Dump-Erfassungsmethoden automatisch eine Garbage Collection durchführen).

Die Speicherbereinigung kann mit jcmd $ {process ID} GC.run generiert werden. Sie können dies auch mit jconsole tun.

In RMI (Remote Method Call) wird "System.gc ()" stündlich als Mechanismus des verteilten Garbage Collector ausgeführt.

Wenn Sie den Aufruf von "System.gc ()" deaktivieren möchten, können Sie dies mit "-XX: + DisableExplicitGC" tun.

Auswahl des Garbage Collection-Algorithmus

Der serielle Garbage Collector ist nur wirksam, wenn der verwendete Speicher 100 MB oder weniger beträgt. Bei den meisten Programmen wird der Durchsatztyp oder der gleichzeitige Typ ausgewählt.

Entscheiden Sie, welche gemäß den in Kapitel 2 beschriebenen Leistungszielen verwendet werden soll. Berücksichtigen Sie die Ausführungszeit der Anwendung, den Durchsatz und die Priorisierung des Durchschnittswerts (oder des 90. Perzentilwerts).

Die gleichzeitige Speicherbereinigung eignet sich für die Stapelverarbeitung, bei der nicht alle CPU-Ressourcen verbraucht werden. Die Garbage Collection vom Durchsatztyp eignet sich für die Stapelverarbeitung, bei der alle CPU-Ressourcen verbraucht werden.

Die CMS-Leistung kann aufgrund begrenzter CPU-Ressourcen, die es sich nicht leisten können, CMS-Hintergrundthreads auszuführen, erheblich beeinträchtigt werden. Dieser Zustand wird als gleichzeitiger Modusfehler bezeichnet.

In Bezug auf die durchschnittliche Antwortzeit ist die Speicherbereinigung vom Durchsatztyp höher. Beim 90. Perzentilwert kann das CMS höher sein.

Grundsätzlich ist CMS schneller als G1, wenn die Heap-Größe 4 GB oder weniger beträgt.

Der CMS-Hintergrundthread durchsucht den gesamten alten Bereich, bevor das Objekt freigegeben wird. Die Zeit zum Scannen ist proportional zur Größe des Bereichs. Wenn der Heap vor dem Scannen und Freigeben von Objekten voll ist, tritt ein Fehler im gleichzeitigen Modus auf. Stoppen Sie in diesem Fall alle Anwendungsthreads und führen Sie eine vollständige Speicherbereinigung durch. Die Leistung leidet, weil in einer vollständigen Garbage Collection nur ein Thread verwendet wird. Es ist möglich, hier mehrere Threads zu verwenden, aber die Verarbeitung jedes Threads wird entsprechend erhöht. Die Wahrscheinlichkeit eines gleichzeitigen Modusfehlers wirkt sich auch auf die Größe des zugewiesenen Speichers aus.

Andererseits wird im G1-Garbage Collector der alte Bereich durch die Region unterteilt, sodass es möglich ist, den Scan des alten Bereichs in einem separaten Thread für jede Region zu verarbeiten. Selbst wenn die Verarbeitung dieser Threads nicht mithalten kann, kann ein gleichzeitiger Modusfehler auftreten, der jedoch aufgrund des Mechanismus nicht sehr häufig auftritt.

In CMS ist es leicht, fragmentiert zu werden, da es mit Ausnahme der vollständigen Speicherbereinigung nicht komprimiert wird.

Es ist unwahrscheinlich, dass eine Heap-Fragmentierung in G1 auftritt.

Sowohl in CMS als auch in G1 gibt es Optimierungsmethoden, um Fehler im gleichzeitigen Modus zu vermeiden.

5.2 Grundlegende Optimierung des Garbage Collectors

Ändern Sie die Heap-Größe

Wenn der Heap klein ist, müssen Sie die ganze Zeit Garbage Collection durchführen. Die Pausenzeit, die während der Speicherbereinigung auftritt, nimmt proportional zur Größe des Heapspeichers zu.

Wenn Sie einen Heap-Bereich angeben, der größer als der physische Speicher ist ... Die JVM unterscheidet nicht, ob es sich um einen Swap-Bereich handelt oder nicht. Daher versuchen Java-Anwendungen, den angegebenen Heap-Bereich vollständig zu nutzen, was sich auf die Leistung auswirkt. Darüber hinaus wird während der vollständigen Speicherbereinigung auf den gesamten Heap zugegriffen, sodass immer ein Austausch stattfindet. Dann ist die Speicherbereinigung nicht rechtzeitig, was zu einem gleichzeitigen Modusfehler führt. Daher sollte ** die Größe des Heapspeichers die Größe des physischen Speichers nicht überschreiten. ** **. Der physische Speicher sollte für die JVM selbst und andere Anwendungen einen Spielraum von 1 GB haben.

Die Heap-Größe wird mit einem Anfangswert von "-XmsN" und einem Maximalwert von "-XmxN" angegeben. Der Standardwert hängt vom Betriebssystem, der Speicherkapazität und dem JVM-Typ ab. Die JVM stellt automatisch zwischen den Anfangs- und Maximalwerten ein. Wenn die aktuelle Heap-Größe zu viel Speicherbereinigung verursacht, erhöhen Sie die Heap-Größe kontinuierlich.

Im Allgemeinen ist es wünschenswert, eine Heap-Größe zu haben, die 30% nach der vollständigen Speicherbereinigung verwendet wird.

Größeneinstellung für jeden Bereich

---XX: NewRatio = N: Verhältnis von altem zu jungem Bereich (Standard ist 2) ---XX: NewSize = N: jung Anfangsgröße der Fläche ---XX: MaxNewSize = N: Die maximale Größe des jungen Bereichs ---XmnN: Kurze Notation, damit NewSize und MaxNewSize den gleichen Wert haben

Die anfängliche Größe der jungen Region wird unten berechnet.

Anfangsgröße des jungen Gebiets=Anfangsgröße des Heaps/(1 + NewRatio)

Standardmäßig beträgt die Anfangsgröße des jungen Bereichs 33% der Anfangsgröße des Heapspeichers (Sie können sie auch mit dem Flag "NewSize" angeben).

Passen Sie die Größe des permanenten Bereichs und des Metaspaces an

Die JVM enthält Daten zur Klasse. Der Bereich wird bis Java 7 als permanenter Bereich und nach Java 8 als Metaspace bezeichnet. Der permanente Bereich von Java7 enthielt verschiedene Informationen, die nichts mit den Daten der Klasse zu tun hatten, aber von Java8 auf den normalen Heap verschoben wurden.

Der permanente Bereich und der Metaspace sind Bereiche, die vom JIT-Compiler und von JVM verwendet werden, sodass sie sich ihrer kaum bewusst sind.

Der permanente Bereich hat eine Obergrenze, aber der Metaspace hat standardmäßig keine Obergrenze (es ist fast nicht erforderlich, die Größe der Obergrenze anzugeben). Wenn du es anziehst Permanente Bereichseinstellungen: -XX: PermSize = N, -XX: MaxPermSize = N Metaspace-Einstellungen: -XX: MetaspaceSize = N, -XX: MaxMetaspaceSize = N

Es gibt Fälle, in denen der Metaspace Speicher belegt, dieser kann jedoch mit NMT (Native Memory Tracking) analysiert werden, das in Kapitel 8 vorgestellt wurde. (Ist es der Fall, wenn das System zu groß wird und die Anzahl der Klassen zunimmt? Es scheint besser, vorher über die Aufteilung der Dienste nachzudenken.)

Das Ändern der Größe permanenter Bereiche und Metaspaces ist langsam, da die Speicherbereinigung erforderlich ist. Wenn die Speicherbereinigung beim Start wiederholt wird, wurden möglicherweise der permanente Bereich und der Metaspace erweitert. Erhöhen Sie in diesem Fall die anfängliche Größe.

Informationen zum Laden von Klassen erhalten Sie mithilfe des in Kapitel 7 beschriebenen Heap-Dumps. Sie können sehen, ob der permanente Bereich oder Metaspace mit Daten aus dem Klassenladeprogramm gefüllt ist. Informationen zum Klassenladeprogramm erhalten Sie, indem Sie jmap mit -clstats ( -permstat für Java 7) starten.

Angabe des Parallelitätsgrades

Anders als beim seriellen Typ wird eine Multithread-Speicherbereinigung durchgeführt. Sie können die Anzahl der Threads mit -XX: ParallelGCThreads = N angeben.

Standardmäßig gibt es einen Thread pro CPU. Wenn dieser Wert jedoch 8 überschreitet, wird die Anzahl der Threads durch die folgende Formel bestimmt.

Anzahl der Threads in der Garbage Collection= 8 + 5(N - 8)/8

Wenn mehrere JVMs ausgeführt werden, sollten Sie die Anzahl der Threads reduzieren.

Da die Effizienz der Speicherbereinigung hoch ist, wird 100% CPU verwendet.

adaptive sizing Die Größe des Heap-Bereichs und des Überlebensbereichs wird während der Ausführung dynamisch geändert. Diese Bewegung wird als adaptive Dimensionierung bezeichnet. Der Vorteil ist, dass selbst wenn Sie einen großen Wert für den Maximalwert festlegen, dieser automatisch erweitert wird, ohne dass Sie den Heap möglicherweise überbeanspruchen, obwohl Sie ihn nicht verwenden.

Das Ändern der Größe erfordert Zeit. Die meisten von ihnen werden von der Speicherbereinigung gestoppt. Wenn Sie die Parameter der Garbage Collection detailliert angeben und die erforderliche Heap-Größe kennen, können Sie die adaptive Größe deaktivieren. Es kann mit -XX: -UseAdaptiveSizePolicy deaktiviert werden.

Wenn Sie -XX: + PrintAdaptiveSizePolicy verwenden, können Sie sehen, wie jeder Bereich erweitert wird.

Tools zur Speicherbereinigung

Es ist eine gute Idee, das Garbage Collection-Protokoll zu überprüfen, um festzustellen, wie stark sich die Garbage Collection auf Ihre Anwendung auswirkt. Mit -verbose: gc oder -XX: + PrintGC wird das GC-Protokoll ausgegeben. -XX: + PrintGCDetails gibt Ihnen ein detaillierteres Protokoll. Geben Sie außerdem "-XX: + PrintGCTimeStamps" oder "-XX: + PrintGCDateStamps" an. Sie können das Ausgabeziel mit -Xloggc: $ {Dateiname} ändern. Die mit der Protokollrotation verbundenen Flags lauten wie folgt. -XX:+UseGCLogFileRotation, -XX:NumberOfGCLogFiles=N, -XX:GCLogFileSize=N Sie können Grafiken und Tabellen erstellen, indem Sie eine Protokolldatei in ein Tool namens GC-Histogramm laden.

jstat -gcutil ${Prozess ID} 1000

Sie können das GC-Protokoll für die Java-Anwendung abrufen.

Recommended Posts

Java-Leistung Kapitel 5 Grundlagen der Garbage Collection
Java-Leistung Kapitel 1 Einführung
Java Performance Kapitel 3 Java Performance Toolbox
Java-Leistung Kapitel 2 Ansatz für Leistungstests
Java-Grundlagen
Java-Grundlagen
Java-Grundlagen
Effektives Java Kapitel 2
Grundlagen der Java-Programmierung
Effektives Java Kapitel 6 34-35
Java Reintroduction-Java Collection
Java JAR-Grundlagen
Objektorientierte (Java) Grundlagen
Grundlagen der Java-Parallelverarbeitung
Müllabfuhr - Teil 1 -
Effektives Java Kapitel 4 15-22
Effektives Java Kapitel 3
[Java] Sammlungsframework
Java-Leistung Kapitel 4 Funktionsweise des JIT-Compilers
Abgelaufene Java-Sammlung
Fragen zum Java-Sammlungsinterview
Leistungsoptimierung für Java-Apps
Java-Programmiergrundlagen Übungsarray
Java Network Basics (Kommunikation)
Muscle Java Basics Tag 1
Kapitel 2 Netzwerkprogrammierung von JAVA phttpd Ausnahmesammlung an 3 Stellen
Erste Schritte mit Java Collection
Ich habe Java Gold gestartet (Kapitel 1-1)
Grundlagen der Zeichenoperation (Java)
Java Parallel Code Sample Collection
G1 Müllabfuhr in 3 Minuten
[Java] Komparator der Collection-Klasse
Sammlung von Java-Testcode-Methoden
Grundlagen der Java-Programmierung Practice-for-Anweisung
Was ist eine Java-Sammlung?
Zusammenfassung der Grundlagen der Java-Sprache
Erste Schritte mit Java Basics
Grundlagen der Java-Entwicklung ~ Übung (Array) ~
[Java-Grundlagen] Was ist Klasse?
Deep Copy Collection in Java
Sammlung ausgewählter Programmieraufgaben zum Erstellen und Erinnern (Java-Grundlagen)