24
Wir nutzen Technologien, um unsere Kunden glücklich zu machen. Und uns selbst. Java-Optimierung Grundlagen, Konfiguration, Methoden und Werkzeuge zur Optimierung von Oracle-Java Vesperbox am Freitag, den 09.11.2012 Daniel Bäurer inovex GmbH Systems Engineer

Java-Optimierung

Embed Size (px)

DESCRIPTION

Grundlagen, Konfiguration, Methoden und Werkzeuge zur Optimierung von Oracle-Java

Citation preview

Page 1: Java-Optimierung

Wir nutzen Technologien, um unsere Kunden glücklich zu machen. Und uns selbst.

Java-OptimierungGrundlagen, Konfiguration, Methoden und Werkzeuge zur Optimierung von Oracle-Java

Vesperbox am Freitag, den 09.11.2012

Daniel Bäurerinovex GmbHSystems Engineer

Page 2: Java-Optimierung

04.12.12

Inhalt

● Grundlagen der Speicherverwaltung von Oracle-Java

● Garbage-Collection und GC-Algorithmen

● Konfiguration des Speichers und des Garbage-Collector

● Methoden zur Optimierung von Oracle-Java

● Werkzeuge zur Optimierung von Oracle-Java

● Weiterführende Referenzen

Page 3: Java-Optimierung

04.12.12

Grundlagen der Speicherverwaltung von Oracle-Java

Oracle-Java allokiert zwei Bereiche im Hauptspeicher:

● Perm-Generation – Speicherbereich, in dem Klassen, Methoden sowie nativ kompilierte Objekte vorgehalten werden, die während der gesamten Laufzeit der JVM vorhanden sind.

● Heap – Speicherbereich, in dem zur Laufzeit der JVM dynamisch Objekte erzeugt, vorgehalten und entfernt werden.

● Der Heap ist weiterhin in zwei Unterbereiche aufgeteilt. Den sogenannten Young- und Old-Generation (auch als Tenured bezeichnet), in denen sich Objekte unterschiedlichen Alters befinden.

● Auch der der Young-Gen wird in Unterbereichen organisiert. Diese werden als Eden, Survivor 1 und Survivor 2 bezeichnet.

Page 4: Java-Optimierung

04.12.12

Grundlagen der Speicherverwaltung von Oracle-Java

Quelle: http://misnad.wordpress.com/2012/03/01/jvm-heap-garbage-collection-volume-1/

● Neue Objekte werden immer (bis auf wenige Ausnahmen) in Eden erzeugt.

● Dynamisch erzeugte Objekte können erreichbar (leben) oder nicht mehr erreichbar (tot) sein.

Page 5: Java-Optimierung

04.12.12

Grundlagen der Speicherverwaltung von Oracle-Java

● Sobald Eden voll ist, werden alle lebenden Objekte in den aktiven Survivor (To genannt) kopiert und alle toten Objekte entfernt.

● Ebenfalls werden alle lebenden Objekte des inaktiven Survivor (From genannt) in den aktiven Survivor kopiert und alle toten Objekte entfernt.

● Beide Survivor-Bereiche tauschen fortwährend ihre Rolle.

● Objekte die ein gewisses Alter (Kopiervorgänge) erreichen, werden in den Old-Generation (Tenured) kopiert.

● Sobald auch Tenured gefüllt ist, bzw. Eden und den aktiven Survivor nicht mehr aufnehmen kann, müssen auch dort alle toten Objekte entfernt werden.

Page 6: Java-Optimierung

04.12.12

Grundlagen der Speicherverwaltung von Oracle-Java

Quelle: http://misnad.wordpress.com/2012/03/01/jvm-heap-garbage-collection-volume-1/

● Aufräumarbeiten in Young-Generation werden als Minor-GC bezeichnet.

● Aufräumarbeiten in Old-Generation werden als Major-GC bezeichnet.

Page 7: Java-Optimierung

04.12.12

Garbage-Collection und GC-Algorithmen

● Im Gegensatz zu manch anderer Programmiersprache, muss sich bei Java nicht der Programmierer um die Speicherreservierung oder -freigabe kümmern.

● Java verwendet zur automatischen Freigabe des Speichers die, bereits angesprochene, Garbage-Collection (GC).

● Für eine Garbage-Collection muss die Anwendung gestoppt werden.

● Eine Garbage-Collection beansprucht CPU-Threads, bzw. Prozessorzeit.

Page 8: Java-Optimierung

04.12.12

Garbage-Collection und GC-Algorithmen

Serial Collector Parallel Collector

Mark Sweep Compact

Concurrent Mark and Sweep Collector (CMS)

Serial Mark, Sweep, Compact

Parallel Compact

Initial Mark

Concurrent Mark

Concurrent Sweep

Remark

Minor-GC

Major-GC

Thread belegt durch die GC

Thread belegt durch die Applikation

Mark-Sweep-Compact Collector (MSC)

Page 9: Java-Optimierung

04.12.12

Garbage-Collection und GC-Algorithmen

● Das Aufräumen der Young-Generation wird durch kopieren erreicht.

● Das Aufräumen der Old-Generation wird durch Reorganisation erreicht, was wesentlich aufwändiger ist.

● Da die Old-Generation im Vergleich zur New-Generation relativ groß ist, dauert ein Major-GC länger.

● Der CMS-Algorithmus fragmentiert den Speicher und falls die Fragmentierung zu stark ist, wird Mark-Sweep-Compact ausgeführt.

● Ebenfalls muss der CMS-Algorithmus rechtzeitig anlaufen um für den nächsten Minor-GC Platz zu schaffen, was einen gewissen Zuschlag für Tenured (bis zu 30%) erfordert. Allerdings kann CMS den GC-Lauf mit der Minor-GC koordinieren.

● Ausblick: Garbage-First GC (G1)

Page 10: Java-Optimierung

04.12.12

Konfiguration des Speichers und des Garbage-Collector

● Die Speichergröße die Young- und Old-Generation (Heap) belegen dürfen, wird mit den Parametern Xms (Minimum) und Xmx (Maximum) angegeben.

● Die Speichergröße des Young-Generation (Eden, Survivor 1, Survivor 2) wird mit den beiden Schaltern NewSize und MaxNewSize eingestellt.

● Die Größe von Eden und eines Survivor (Survivor 1 = Survivor 2) kann man nur über die Angabe des SurvivorRatio einstellen:

● Auch die Größe von Tenured (Old-Generation) ergibt sich nur indirekt:

● Die Größe der Perm-Generation kann man wieder direkt einstellen und zwar mit den Schaltern PermSize (initiale Größe) und MaxPermSize (maximale Größe)

Eden=SurvivorRatio

SurvivorRatio+2∗MaxNewSize Survivor=

MaxNewSizeSurvivorRatio+2

Tenured=Xmx−MaxNewSize

Page 11: Java-Optimierung

04.12.12

Konfiguration des Speichers und des Garbage-Collector

Eden S1 S2

SurvivorRatio=2: Eden=2/4, S1=1/4, S2=1/4

Eden S1 S2

SurvivorRatio=8: Eden=8/10, S1=1/10, S2=1/10

Quelle: http://misnad.wordpress.com/2012/03/01/jvm-heap-garbage-collection-volume-1/

Page 12: Java-Optimierung

04.12.12

Konfiguration des Speichers und des Garbage-Collector

● Keine dynamische Größenanpassung des Speichers ermöglichen, sondern immer Xms = Xmx, bzw. NewSize = MaxNewSize konfigurieren.

● Bytegrößen können mit k (KB), m (MB), g (GB), t (TB) angegeben werden, beispielsweise Xmx2g, MaxNewSize=512m.

● Ab wann Objekte soweit gealtert sind, dass sie aus dem Young-Generation in den Old-Generation kopiert werden, wird mit dem Schalter MaxTenuringThreshold eingestellt.

● Ein MaxTenuringThreshold von 10 bedeutet, dass ein Objekt 10 mal im Young-Generation kopiert werden kann, bevor es in Tenured kopiert wird.

● Für eine bessere Unterstützung von Multiprozessormaschinen kann „Non-Uniform Memory Access“ (UseNUMA) sowie „Thread-local allocation Buffer“ (UseTLAB) verwendet werden.

Page 13: Java-Optimierung

04.12.12

Konfiguration des Speichers und des Garbage-Collector

● Der Serielle-Garbage-Collector (UseSerialGC) dürfte dank moderner CPU-Technik vermutlich nur noch für Client-Anwendungen Verwendung finden.

● Mit UseParallelGC wird der parallele Garbage-Collector gewählt, der für das bereinigen des Young-Generation verantwortlich ist.

● Sofern man den CMS-GC verwendet, sollte man als parallelen Garbage-Collector den UseParNewGC verwenden. Dieser kann mit dem CMS-GC interagieren und so gemeinsame GC-Läufe koordinieren.

● Wichtig bei der Benutzung der parallelen GC-Algorithmen ist, dass die Threadanzahl, die verwendet werden soll, explizit mittels des Schalters ParallelGCThreads eingestellt wird.

Page 14: Java-Optimierung

04.12.12

Konfiguration des Speichers und des Garbage-Collector

● Das parallele Compacting des Mark-Sweep-Compact Garbage-Collector wird mit dem Schalter UseParallelOldGC aktiviert. Für die maximale Anzahl der GC-Threads wird der Wert von ParallelGCThreads verwendet.

● Um den CMS-GC zu aktivieren, wird der Schalter UseConcMarkSweepGC benutzt. Der CMS-GC besitzt einen eigenen Schalter für die maximal zu verwendenden Threads, ParallelCMSThreads.

● Das parallele Remarking des CMS sollte ebenfalls explizit aktiviert werden, CMSParallelRemarkEnabled.

● Um manuelle ausgelöste Garbage-Collector-Läufe zu unterbinden, sollten diese explizit mit dem Schalter DisableExplicitGC nicht ermöglicht werden.

Page 15: Java-Optimierung

04.12.12

Methoden zur Optimierung von Oracle-Java

● Um Oracle-Java vernünftig optimieren zu können, müssen zu Beginn eine Reihe von Logging-Paramtern aktiviert werden, um aussagekräftige Messwerte zu erhalten.

verbose:gcPrintGCPrintGCDetailsPrintHeapAtGCPrintGCTimeStampsPrintGCDateStampsPrintGCApplicationStoppedTimePrintGCApplicationConcurrentTimePrintTenuringDistribution

● Neben den Messwerten, benötigt man für die Optimierung auch eine realistische Last. Ohne diese ist eine Optimierung relativ sinnlos!

● Das Vorgehen zur Optimierung sollte so gewählt werden, dass jeder Funktionsbereich (Eden, Survivor, Tenured, Alterung, Minor-GC, Major-GC) separat betrachtet wird.

Page 16: Java-Optimierung

04.12.12

Methoden zur Optimierung von Oracle-Java

● Die Wahl des richtigen Garbage-Collector für die Minor-GC ist, wie bereits angedeutet, aus Sicht heutiger Multiprozessor-Systeme relativ einfach. Es sollte der parallele GC verwendet werden und die Anzahl der zu verwendenden Threads ermittelt werden.

● Zur Bestimmung der Größe von Eden muss berücksichtigt werden:

● Desto größer Eden ist, desto weniger Minor-GCs finden statt.● Desto mehr Objekte in Eden sterben, desto besser.● Wie Altern die Objekte der Java-Anwendung?

● Bestimmen der Größe von Eden:

● Setze Eden sehr groß

● Ermittle die Allokationsrate:

● Passe Eden an:

Allokationsrate=Größe Eden

Intervall MinorGC

Eden=Allokationsrate∗(Zielintervall MinorGC∗Reserve)

Page 17: Java-Optimierung

04.12.12

Methoden zur Optimierung von Oracle-Java

● Bei der Optimierung des Survivor-Bereich sollte beachtet werden:

● Desto kleiner der Survivor-Bereich ist, desto eher werden Objekte nach Tenured verschoben die nicht mehr lange leben.

● Bleiben langlebende Objekte zu lange im Survivor-Bereich, werden diese unnötig oft kopiert.

● Bestimmung des Survivor-Bereichs:

● MaxTenuringThreshold sehr hoch einstellen.

● Erkennt man bei der Betrachtung der Altersverteilung, dass Objekte mit der Zeit erheblich „ausaltern“ und ab einem gewissen Alter nicht mehr so stark, dann ist dies der beste Wert für MaxTenuringThreshold.

● Altern Objekte hingegen nicht merklich aus, dann kann man MaxTenuringThreshold auf einen sehr kleinen Wert (2-3) einstellen.

Page 18: Java-Optimierung

04.12.12

Methoden zur Optimierung von Oracle-Java

● Zur Ermittlung des Survivor-Ratio macht man diesen zu Beginn wieder recht groß und schaut welchen Füllgrad er über den Lauf der Zeit im Schnitt annimmt.

● Mit dem so ermittelten Wert, kann man die Survivor-Größe indirekt einstellen.

Quelle: http://www.angelikalanger.com/Articles/EffectiveJava/49.GC.GenerationalGC/49.GC.GenerationalGC.html

Page 19: Java-Optimierung

04.12.12

Methoden zur Optimierung von Oracle-Java

● Für die Wahl des Garbage-Collector der Major-GC kann man den Mark Sweep Compact benutzen, wenn

● relativ lange Pausenzeiten kein Problem ist.● Tenured relativ klein ist.● Probleme mit CMS auftreten.

● In den meisten Fällen dürfte die Wahl auf den CMS Garbage-Collector fallen.

● Beim Mark-Sweep-Compact GC sollte paralleles Compact aktiviert werden und bei CMS die Anzahl der parallelen Threads explizit gesetzt werden.

● Es kann dennoch nicht schaden, beide Garbage-Collectoren miteinander zu vergleichen.

Page 20: Java-Optimierung

04.12.12

Methoden zur Optimierung von Oracle-Java

● Bei der Optimierung von Tenured sollte beachtet werden:

● Desto größer Tenured desto weniger Major-GC finden statt.● Desto größer Tenured desto länger die Laufzeit der Major-GC.● Ein zu kleiner Tenured führt zu häufigen Major-GCs.● Desto mehr langlebige Objekte in Tenured betrachtet werden

müssen desto länger die Laufzeit der Major-GC.

● Bestimmung der Größe von Tenured:

● Die minimale Größe von Tenured ist direkt nach einem Major-GC zu ermitteln.

● Ermittle das durchschnittliche Volumen das bei einer Minor-GC aus der Young-Generation nach Tenured kopiert wird.

● Nun kann man anhand eines Zielintervalls der Major-GC die benötigte Tenured-Größe bestimmen:

Tenured=MajorGC Zielintervall

MinorGCIntervall

∗∅VolumenMinorGC

Page 21: Java-Optimierung

04.12.12

Methoden zur Optimierung von Oracle-Java

● Die Speichergröße der Perm-Generation ist relativ statisch.

● Um die Größe der benötigten MaxPermSize zu ermitteln, stellt man diese recht große ein und betrachtet sie über einen längeren Zeitraum.

● Hier wird sich im laufe der Zeit eine Sättigung einstellen, welche als Größe für MaxPermSize (+Puffer) verwendet werden kann.

Page 22: Java-Optimierung

04.12.12

Werkzeuge zur Optimierung von Oracle-Java

● Loglevel hoch drehen

● Logdatei betrachten

● Auswertung mit Scripten

● GCViewer https://github.com/chewiebug/GCViewer/wiki/Changelog

● PsiProbe https://code.google.com/p/psi-probe/downloads/list

Page 23: Java-Optimierung

04.12.12

Weiterführende Referenzen

● Oracle-JVM-Options:http://www.oracle.com/technetwork/java/javase/tech/vmoptions-jsp-140102.html

● Tuning-Guide von Oracle:http://www.oracle.com/technetwork/java/javase/gc-tuning-6-140523.html

Page 24: Java-Optimierung

04.12.12

Vielen Dank für Ihre Aufmerksamkeit!

inovex GmbH

PforzheimKarlsruher Straße 71D-75179 Pforzheim

MünchenValentin-Linhof-Straße 2D-81829 München

KölnSchanzenstraße 6-20D-51063 Köln