//

Nützliche JVM Flags – Teil 1

8.3.2011 | 6 Minuten Lesezeit

Moderne Java Virtual Machines (JVMs) besitzen ein beeindruckendes Spektrum von Fähigkeiten, um Java-Anwendungen effizient und stabil auszuführen: Adaptive Speicherverwaltung, Garbage Collection, JIT-Compiler, dynamisches Classloading, Lock-Optimierung und vieles mehr. Zur Laufzeit der Anwendung optimiert die JVM basierend auf Messungen das Zusammenspiel ihrer Algorithmen – und das vollkommen transparent für Entwickler und Benutzer. Der über die Jahre hinweg erzielte Fortschritt in der JVM-Technologie spielt nicht nur eine wesentliche Rolle beim anhaltenden Erfolg von Java, er hat auch den Weg für eine Reihe weiterer Programmiersprachen bereitet, die JVM-kompatiblen Bytecode generieren und so die Vorteile der JVM für sich nutzen.

Bei so viel Automatik sind Mechanismen zum Monitoring und Performance-Tuning von Anwendungen sehr wichtig. Im Fehlerfall oder bei ungenügender Performance soll die Ursache schnell und sicher ermittelbar und idealerweise durch gezieltes Tuning korrigierbar sein. Auch hier glänzt die JVM mit einer Fülle von Konfigurationsmöglichkeiten und Tools. Besonders interessant für den Bereich Performance-Tuning sind die Kommandozeilen-Flags, die man beim Start der JVM setzen kann. Es gibt allerdings mehrere Hundert solcher Flags, so dass man leicht den Überblick verlieren kann. In dieser Blog-Serie werden wir die besonders relevanten Flags aus der Masse extrahieren, diese näher kennenlernen und ihre Einsatzgebiete verstehen.

Bevor es losgeht, noch ein paar Worte zur Organisation: Wir werden uns sowohl mit einfachen Standard-Flags der Kategorie „Sollte jeder kennen“ als auch mit ungewöhnlichen Flags (die man zwar selten einsetzt, aber von denen man viel über die JVM lernen kann) beschäftigen. Themenverwandte Flags werde ich in einem Eintrag bündeln, wann immer ich das für sinnvoll halte. Die Darstellung bezieht sich ausschließlich auf die HotSpot JVM des Sun/Oracle JDK 6. Andere JVMs bieten aber oft vergleichbare Flags an, ggf. mit anderen Namen, so dass man hier indirekt auch über diese etwas lernen kann.

-server und -client

Es gibt zwei Typen der HotSpot-JVM, nämlich „Server“ und „Client“. Die Server-VM verwendet großzügigere Einstellungen für den Heap, nutzt per Default einen parallelen Garbage Collector und führt zur Laufzeit aggressivere Code-Optimierung durch. Die Client-VM verhält sich konservativer und reduziert dadurch Startup-Zeit und Memory-Footprint. Für die Auswahl der JVM werden Rechner anhand bestimmter Kriterien bzgl. ihrer Hardware und ihres Betriebssystems nach Client- und Server-Klasse unterschieden. Auf einem Rechner der jeweiligen Klasse wird automatisch die entsprechende JVM gestartet. Die aktuellen Kriterien lassen sich hier nachlesen.

Möchte man selbst bestimmen welche JVM verwendet wird, so kann man dazu die Flags -server bzw. -client nutzen. Obwohl die Server-VM ursprünglich vor allem auf die Verwendung für lang laufende Server-Prozesse ausgerichtet war, zeigt sie heutzutage auch in vielen Standalone-Anwendungen teilweise deutlich bessere Performance als die Client-VM. Meine Empfehlung ist, die Server-VM immer dann zu verwenden, wenn Performance im Sinne kurzer Laufzeit bzw. schnellstmöglicher Verarbeitung wichtig ist. Dies stellt man durch das Setzen des -server Flags sicher. Zu beachten ist, dass man ggf. ein JDK (und nicht nur ein JRE) installieren muss, um die Server-VM verwenden zu können.

-version und -showversion

Wie können wir herausfinden, welche JVM verwendet wird wenn wir java aufrufen? Wenn sich mehrere Java-Installationen auf einem System befinden (besonders gefährlich sind hier vorinstallierte JVMs), dann besteht immer ein gewisses Risiko, aus Versehen die falsche JVM zu starten. An dieser Stelle hilft das Flag -version, das Informationen über die verwendete JVM ausgibt und dem Benutzer damit viel Ärger ersparen kann. Ein Beispiel zur Verwendung des Flags:

1$ java -version
2java version "1.6.0_24"
3Java(TM) SE Runtime Environment (build 1.6.0_24-b07)
4Java HotSpot(TM) Client VM (build 19.1-b02, mixed mode, sharing)
5

Wir sehen hier die Versionsnummer (1.6.0_24) und die exakte Build-ID des verwendeten JRE (1.6.0_24-b07). Außerdem sehen wir den Namen (HotSpot), den Typ (Client) und die Build-ID (19.1-b02) der verwendeten JVM. Zusätzlich erhalten wir noch Informationen über das Verhalten der JVM. Sie verwendet den Mixed-Mode („mixed mode“), d.h. sie übersetzt Bytecode zur Laufzeit dynamisch in Maschinencode. Dies ist das Standardverhalten von HotSpot. Ebenso erfahren wir, dass Class Data Sharing („sharing“) aktiviert ist, d.h. die System-Klassen des JRE befinden sich in einem Read-Only-Cache (.jsa-Datei, „Java Shared Archive“), der beim Classloading von mehreren JVM-Prozessen gemeinsam genutzt wird. Dies kann die Performance gegenüber einem ständigen erneuten Einlesen und Verifizieren der Klassen aus jar-Archiven verbessern. Zu beachten ist, dass Class Data Sharing nur von der Client-VM unterstützt wird.

Ein potentieller Nachteil bei der Verwendung von -version ist, dass die JVM sich unmittelbar nach der Ausgabe beendet, die eigentliche Anwendung also nicht ausgeführt wird. Hier schafft das Flag -showversion Abhilfe, welches die gleichen Ausgaben wie -version liefert und im Anschluss auch die eigentliche Anwendung ausführt. Mit -showversion kann man also prima Informationen über die verwendete JVM loggen, die sich zu einem späteren Zeitpunkt als nützlich erweisen können.

-Xint, -Xcomp und -Xmixed

Wir haben den Mixed-Mode der JVM oben bereits kurz kennengelernt. Nicht unbedingt für den Alltagsgebrauch bestimmt, aber doch sehr interessant für Experimente sind die Flags -Xint und -Xcomp. Mit -Xint zwingt man die JVM, sämtlichen Bytecode ausschließlich interpretiert auszuführen, was zu einer deutlichen Verlangsamung führt (in der Regel um ca. Faktor 10). Mit -Xcomp hingegen kann man das exakt umgekehrte Verhalten erreichen, d.h. sämtlicher Bytecode wird sofort mit maximaler Optimierungsstufe kompiliert. Das hört sich zunächst einmal sehr gut an, denn so kann man den langsamen Interpreter komplett umgehen. Dennoch werden viele Anwendungen durch die Verwendung von -Xcomp ebenfalls verlangsamt werden, wenn auch nicht so stark wie im Fall von -Xint. Der Grund dafür ist, dass wir der JVM mit -Xcomp die Möglichkeit nehmen, ihren JIT-Compiler effektiv einzusetzen. Der JIT-Compiler erstellt zunächst Nutzungsprofile einzelner Methoden und optimiert deren Code dann gezielt (und teilweise spekulativ) auf das tatsächliche Verhalten der Anwendung. Auch werden Methoden nur dann kompiliert, wenn sie sich dessen tatsächlich als würdig erweisen, d.h. intensiv genug genutzt werden um einen Hotspot darzustellen.

Betrachten wir zur Illustration die Ergebnisse eines einfachen Beispiel-Benchmarks, bei dem eine HashMap mit Objekten gefüllt wird und diese anschließend wieder ausgelesen werden. Das berechnete Ergebnis ist der Mittelwert der Ausführungszeiten einer großen Anzahl von Läufen des Benchmarks.

1$ java -server -showversion Benchmark
2java version "1.6.0_24"
3Java(TM) SE Runtime Environment (build 1.6.0_24-b07)
4Java HotSpot(TM) Server VM (build 19.1-b02, mixed mode)
5 
6Average time: 0,856449 seconds
7
1$ java -server -showversion -Xcomp Benchmark
2java version "1.6.0_24"
3Java(TM) SE Runtime Environment (build 1.6.0_24-b07)
4Java HotSpot(TM) Server VM (build 19.1-b02, compiled mode)
5 
6Average time: 0,950892 seconds
7
1$ java -server -showversion -Xint Benchmark
2java version "1.6.0_24"
3Java(TM) SE Runtime Environment (build 1.6.0_24-b07)
4Java HotSpot(TM) Server VM (build 19.1-b02, interpreted mode)
5 
6Average time: 7,622285 seconds
7

Natürlich finden sich auch Benchmarks, bei denen -Xcomp vorteilhaft ist. Gerade bei lang laufenden Anwendungen ist es aber wenig ratsam, auf die Finessen des JIT-Compilers und das dynamische Optimierungspotential der JVM zu verzichten, denn die Performance-Unterschiede können hier wesentlich drastischer ausfallen als bei dem oben gezeigten Benchmark. Abschließend sei noch erwähnt, dass Mixed-Mode auch sein eigenes Flag besitzt, -Xmixed, welches aber standardmäßig aktiviert ist und deshalb nicht gesetzt werden muss.

Schlusswort

Es gibt bestimmt noch mehr über die vorgestellten JVM Flags zu sagen, deshalb ergänzt ruhig in den Kommentaren alles was ihr für wichtig haltet oder beschreibt wie ihr die Flags gewinnbringend einsetzen konntet. Und wenn ihr Interesse an bestimmten Flags habt die ich in einem der folgenden Beiträge vorstellen soll, schreibt doch einfach einen Vorschlag und ich werde sehen was ich tun kann.

Beitrag teilen

Gefällt mir

0

//

Weitere Artikel in diesem Themenbereich

Entdecke spannende weiterführende Themen und lass dich von der codecentric Welt inspirieren.

//

Gemeinsam bessere Projekte umsetzen

Wir helfen Deinem Unternehmen

Du stehst vor einer großen IT-Herausforderung? Wir sorgen für eine maßgeschneiderte Unterstützung. Informiere dich jetzt.

Hilf uns, noch besser zu werden.

Wir sind immer auf der Suche nach neuen Talenten. Auch für dich ist die passende Stelle dabei.