Software Engineering

JavaLand 2015: die besten Präsentationen über Java Performance

Beim Javaland 2015 gab es verschiedene Vorträge über neuen Technologien und Paradigmen wie IoT, JavaFX and NoSql zu hören. Im Bereich „Java Core“ wurden drei sehr gute Vorträge über Java Performance gehalten, die ich hier kurz zusammenfasse.

The (not so) dark art of performance tuning

Kid Pepperdine von Kodewerk Ltd. hat uns anhand eines Leitfaden die Durchführung einer Performanceanalyse gezeigt. Die Idee hinter seinem Prinzip ist ganz einfach: zuerst Messungen durchführen und Fakten sammeln anstatt Maßnahmen umzusetzen, die das Hauptproblem nicht lösen. In vielen Projekten werden Performance-Maßnahmen durchgeführt, die nichts bringen aber viel Geld und Zeit kosten. Diese ersten Fakten und Messungen sollen eine ganz klare Frage beantworten: liegt das Problem am System, an der JVM oder an der Anwendung? Systemprobleme beziehen sich auf Netzwerklatenz, IO oder Speicher. Ein Systemproblem liegt normalerweise vor, wenn die System CPU Time 10% größer als die User CPU Time ist. Es gibt verschiedene Tools, um Anwendung oder JVM Probleme zu identifizieren wie zum Beispiel Mission Control oder VisualVM. Mit Hilfe von Threaddumps, Heapdumps, Allocation Logs und GarbageCollector Logs ist es möglich zu identifizieren ob das Performanceproblem bei der Anwendung oder bei der JVM liegt.

Der Just-In-Time Compiler, das unbekannte Wesen

Fabian Lange von codecentric AG hat über den bekannten aber nicht so gut verstandenen Just In Time Compiler, kurz JIT, berichtet. Java war eine rein interpretierte Sprache bevor der JIT Compiler entwickelt wurde. In Java wird immer der Sourcecode mit Hilfe von javac in ein binäres Format transformiert. Dieses Format wird zur Laufzeit von der JVM interpretiert und in Maschinencode transformiert. Interpretierte Sprachen sind nicht so performant wie kompilierte Sprachen (wie C/C++), weil diese Sprachen die Interpretation zur Laufzeit durchführen müssen. Der JIT Compiler wurde implementiert um dieses Problem zu adressieren. Zur Laufzeit analysiert der JIT Compiler den aktiven Code um die Hotspots zu identifizieren. Hotspots sind die meist durchgeführten Befehle in eine Anwendung. Diese Hotspots werden dann zur Laufzeit vom JIT in Maschinencode transformiert damit sie nicht mehr interpretiert werden. Damit gewinnt Java an Performance und verhält sich an vielen Stellen wie eine kompilierte Sprache.

JIT bringt noch einen weiteren Vorteil, den die kompilierten Sprachen nicht haben. Beim Kompilieren wird der Sourcecode in binären/Machinencode transformiert und auch parallel optimiert. Diese Optimierung basiert in vielen Fällen auf Vermutungen, die der Compiler über den Sourcecode macht. Aber ein statischen Compiler wie gcc oder javac kann nicht wissen wie sich der Code zur Laufzeit verhalten wird. JIT dagegen ist in der Lage dieses Verhalten dynamisch analysieren. Damit kann JIT weitere vertiefte Optimierungen durchführen, die die Performance einer Java-Anwendung deutlich steigern.

Speed up your Java by turning it into binary

John Davies von C24 hat ein sehr interessantes Verfahren präsentiert um die Performance von Java-Anwendungen zu steigern: die Manipulation von Daten in binäre Arrays anstelle der Nutzung von normalen Javaobjekten. Der Hintergrund ist ganz klar. Java ist sehr schlecht in Bezug auf Speicherverwaltung. In Java ist ein normaler String wie „ABC“ größer als 30 Bytes, in anderen Sprachen nur 3 Bytes, weil Java sehr viel zusätzliche Metainformation von seinem Objekt speichert. Dieser Speicherverbrauch ist sehr schädlich für die Perfomance von Java. Denn größere Objekte bedeuten auch mehr Allocation, Fragmetierung und Garbage Collection. Auch in Bezug auf IO und die Datenübertragung über das Netzwerk gibt es Schwächen. Mehrere Bytes generieren mehre Pakete, die das TCP Protokoll verwalten muss. Dieses Problem wird auch deutlich bei alten Legacy Systemen, die Java 4 oder ältere Versionen nutzen, und das Heap nicht unendlich vergrößern können.

IMG_0579

John Davies in Action

Die neuen Java Versionen adressieren dieses Problem nicht und darum sollte man in einigen Fällen die Javaobjekte besser in Byte Arrays serializieren. Leider ist die Out oft the Box Java Serializierung nicht optimal, da Java auch sehr viele Metadaten speichert. John Davies zeigte uns wie man mit „old fashioned“ Techniken, die man vor 30 Jahren in C benutzt hat, diese Serializierung implementieren kann um die Performance deutlich zu steigern. Diese Techniken beinhalten unter anderem Byte Manipulation wie Left-Switch und Rigth-Switch und andere basische Operationen. In seinem Beispiel hat uns John Davies gezeigt wie diese Techniken eine Java Anwendung um das Hundertfache beschleunigte.