Java Performance Tuning Performance Tuning is similar to playing a strategy game but happily you usually get paid for it. Schlechte Performanz kaschieren Bernhard Mähr Eigentlich kein Tuning Benutzer findet das Programm schnell Responsabiltiy Trennung von UI und Arbeits-Thread Animationen um Wartezeiten zu „verkürzen“ siehe zB Fading-Effekte in WindowsXP Vorarbeiten zB während Texteingaben durchführen gibt dem Benutzer das Gefühl einer blitzschnellen Anwendung Java Performance Tuning 2/25 Allgemeines Bernhard Mähr Sollte erst an der fertigen Anwendung durchgeführt werden Performance Tuning widerspricht meist objektorientiertem Design Code wird unübersichtlicher Aber: Beim Application-Design Performance nicht ignorieren Änderungen können auf anderen Platformen Performanz-Nachteile bringen Neusten Compiler verwenden Java Performance Tuning 3/25 Schritte 1. 2. 3. 4. 5. 6. 7. 8. 9. 10. Bernhard Mähr Benchmark einbauen und Tests ausführen Bottlenecks identifizieren Eines aus den Top 5 Bottelnecks wählen (abhängig von bremsender Wirkung und Behebbarkeit) Ausgewählte(s) Methode/Datenstruktur/Objekt/… analysieren Eine Änderung durchführen Perfomance-Messung durchführen Falls die Änderung nicht den gewollten Effekt erzielte vielleicht einen Schritt zurück Solange noch Verbesserungen möglich sind weiter bei Schritt 4 Messung der Gesamtverbesserung Wieder mit Schritt 1 beginnen da sich meist das gesamte Perfomance-Profil geändert hat Java Performance Tuning 4/25 Bottelneck auswählen Bernhard Mähr Programmteil der viel Rechenzeit verwendet Methode mit 1% Rechenzeit -> max. 1% schneller wenn Algorithmus um 100% schneller Methode mit 10% Rechenzeit um 50% schneller -> Gesamtperformance um 5% besser Nur das Tunen was wirklich bremst Java Performance Tuning 5/25 Compiler Optimierungen arr[1]=arr[1]+5; -> arr[1]+=5; y=x/2; -> y=x>>1; z=x*4; -> z=x<<2; T y = new T(5); T x = (T)y; int x = 0; int x = 1; x = 2; int duration = 24*60*60; String s = „“ + 24 + „hours “ + „online“; Dummy case-Zweige für Switch-Anweisungen Bernhard Mähr Java Performance Tuning 6/25 Inlineing Bernhard Mähr final, private und static Methoden können eingefügt werden. Geschieht meist nur private int m1() { return 5; } keine lokalen Variablen private int m2() { return m1(); wenn } verwendet werden public interface A { public static final boolean DEBUG = false; } public class B { public static int foo() { if (A.DEBUG) System.out.println(„Check“); return 0; Der Compiler aus dem SDK führt } Inlining nur bei Konstanten aus } Interfaces aus. Die If-Anweisung wird zur Compilezeit komplett entfernt. Java Performance Tuning 7/25 Optimierungen in Standardanweisungen Bernhard Mähr Datentyp int ist schneller als long, byte, short,… Zugriff auf lokale Variablen ist schneller als Zugriff auf static Variablen Zugriff auf einfache Variablen ist schneller als Zugriff auf Arrays oder Objekte Kurzschluß-Auswertung beachten //statt if (n == Integer.MIN_VALUE || n>0){ //lieber if (n>0 || n == Integer.MIN_VALUE){ Native-Methoden verwenden wenn möglich (zB arraycopy() statt Schleife) Zugriff auf eindimensionale Arrays ist schneller wie auf mehrdimensionale Java Performance Tuning 8/25 Canonicalization Bernhard Mähr public interface GENDER { public static final int FEMALE=1; public static final int MALE=2; } if (user.gender==FEMALE) {…} //Inlining durch Complier public class STATUS { public static final String ONLINE=„Online“; public static final String OFFLINE=„Offline“; } if (user.state==STATUS.ONLINE) {…} Boolean t1 = new Boolean(true); Boolean.TRUE; System.out.println(t1==Boolean.TRUE); //false System.out.println(t1.equals(Boolean.TRUE)); //true Java Performance Tuning 9/25 Objekte Bernhard Mähr Erzeugung und GC ist aufwendig Möglichst wenige Objekte verwenden TypeCasts sind teuer instanceof abfragen statt Exception von TypeCast abfangen Einfache Datentypen statt Objekten Objekte wiederverwenden -> Objektpool Objekte im voraus erzeugen Java Performance Tuning 10/25 Initialisieren vs Clonen Bernhard Mähr static int[] Ref_a1 = {1,2,3,4,5,6,7,8,9}; static int[][] Ref_a2 = {{1,2},{3,4},{5,6},{7,8}}; int[] a1 = {1,2,3,4,5,6,7,8,9}; //schneller als int[] array1 = (int [])Ref_a1.clone(); int[][] a2 = (int [][])Ref_a2.clone(); //schneller als int[][] a2 = {{1,2},{3,4},{5,6},{7,8}}; Komplizierte Objekte können schneller geklont als initialisiert werden Mittels Factory-Pattern sehr gut implementierbar private static Something MASTER = new Something(); public static Something getNewSomething() { return (Something) MASTER.clone(); } Java Performance Tuning 11/25 Wiederverwenden von Parameter-Objekten Bernhard Mähr public Dimension setSize(Dimension d) { … d.width=5; d.height=10; return d; } Probleme? realSize = O.setSize(wantedSize); wantedSize.height=7; //realSize.height = ? Lösungen: class FixedDimension { final int height; final int width; } Alle Methoden müssen für die Verwendung von FixedDimension geändert werden Java Performance Tuning 12/25 Wiederverwenden von Parameter-Objekten Bernhard Mähr private static final Dimension D = new Dimension(0,0); public Dimension setSize(Dimension d) { Dimension newd = (Dimension)D.clone(); setSize(d, newd); return newd; } public void setSize(Dimension d, Dimension retd) { … retd.width = 5; retd.height = 10; } Verwendung wie bisher, für Performance-Tuning kann die 2te Methode verwendet werden o.setSize(d,d); Java Performance Tuning 13/25 Schleifen for(long i=0; i<collection.size(); i++) { countArr[0]=countArr[0] + 5 * points; } Unnötige Anweisungen aus der Schleife entfernen Methoden-Aufrufe minimieren Array-Zugriffe vermeiden Umgekehrte FOR-Schleife int intcount=countArr[0]; addpoints = points * 5; count=countArr[0]; int intaddpoints=5*points; addpoints iter addpoints=5*points; = collection.size()*50000; = points; points * 5; for(int i=collection.size(); --i>=0; ){ int i=collection.size()*50000; addpoints iter count count=countArr[0]; ==collection.size()*50000; countArr[0]; = points; count+=addpoints; for(long for(int for(; --i>=0; i=0; i=collection.size()*50000; i=iter; i=0;i<iter; i<collection.size()*50000; i<iter; ){--i>=0;) i++) i++) {{{ --i>=0; i++) ){ { } count+=addpoints; countArr[0]=countArr[0] count=count count+= count=count countArr[0]=countArr[0] addpoints; ++addpoints; addpoints; ++5 addpoints; 5**addpoints; points; countArr[0]=count; } countArr[0] = count; countArr[0]=count; Laufzeit Laufzeit Laufzeit Laufzeit Bernhard Mähr 1.3.1 1.3.1 1.4.1 1.4.1 Code Code Code Code / / / / 1.1.8 No JIT: 1.1.8: 1.4.1 Client: 1.4.1 Server: Java Performance Tuning 39,997 228,559 128,505 98,862 44,384 41,610 225,844s s/ /194% 146,100 44,474 40,769 480% 216% 202% 198% 1111% 624% 1097% 710% 3,305 3,705 1,533 1,513 1,512 2,864 s / 7% 3,505 1,602 16% 18% 14% 17% 8% 36,813 14,591 11,897 6,900 7,651 7,691 31,845s s/ /37% 14,331 6,980 6,229 34% 30% 155% 71% 58% 70% 25,046 4,136 4,116 0,701 0,711 20,580s s/s/20% /3% 20% 122% 100% 14/25 Schleifen / Exceptions Bernhard Mähr Exception Terminated Loops try { for(int i=0;;i++) {…} } catch (Exception e) {} Bei vielen Schleifendurchläufen schneller aber nicht sauber Try-Blocks ohne geworfene Exception bremsen aber nicht viel (bis JDK 1.1.8) Try-Blocks mit geworfener Exception sind deutlich langsamer und sollten im normalen Programmablauf nicht vorkommen Java Performance Tuning 15/25 Rekursionen Bernhard Mähr public static long fact_rec (int n) { return n*fact_rec(n-1); } public static long fact_iter (int n) { long result = 1; while (n>1) { result *= n--; } return result; } Iterative Version braucht nur 88% der Zeit Gecachte Zwischenergebnisse: 4% Java Performance Tuning 16/25 Laden beschleunigen Bernhard Mähr Spash-Screen Unkompremierte JAR-Archive Preload von Klassen (Achtung: Caching der VM nicht behindern) Lazy-Initialisation Java Performance Tuning 17/25 String / StringBuffer Bernhard Mähr Insert, Append, Delete ist auf StringBuffer viel schneller als auf Strings Substring auf String kopiert nichts -> schnell toString() auf StringBuffer kopiert nichts -> schnell allerdings wird Größe nicht verkleinert Java Performance Tuning 18/25 Threads/Synchronized Bernhard Mähr Falsch eingesetzte Threads und jedes Synchronized bremst Ein Thread, der die Aufgaben an einen anderen übergibt, und dann auf deren Beendigung wartet ist sinnlos und langsam! Syncronized Methoden sind 10 mal (mit JIT Compilern) bis 100 mal langsamer Synchronisierte Objekte verwenden und bei Performance-Problemen auf die Unsynchronisierten ausweichen. Java Performance Tuning 19/25 Syncronized Wrappers für eigene Klassen Bernhard Mähr public interface Adder { public void add(int aNumber); } public class UnsyncedAdder implements Adder { int total; int numAdditions; public void add(int add){ total+=add; numAdditions++;} } public class SyncedAdder implements Adder { Adder a; public SyncedAdder(Adder a) { this.a = a; } public synchronized void add( int add) { a.add(add); } } Java Performance Tuning 20/25 Collections Interface Class Sync Eigenschaften Map HashMap Nein Schnellstes Map HashTable Ja Langsamer als HashMap aber schneller als sync. HashMap TreeMap Nein Langsamer als HashTable; Geordnete Iteration der Keys möglich HashSet Nein Schnellstes Set; Langsamer als HashMap aber Set TreeSet Nein Langsamer als HashSet; Geordnete Iteration der Keys möglich ArrayList Nein Schnellste Liste Vector Ja Langsamer als ArrayList aber schneller als sync ArrayList Stack Ja Gleich schnell wie Vector; LIFO Queue LinkedList No Langsamer als andere List-Klassen; für Spezial-Fälle schneller Set List Bernhard Mähr Java Performance Tuning 21/25 Selber implementieren? Bernhard Mähr Sind die Implementierungen der Java-Libaries optimal? An den Verwendungszweck angepaßte Implementierung senkt die Ausführungszeit auf bis zu 0.7% Selbstgeschriebene IntArrayList statt der ArrayList verwenden Java Performance Tuning 22/25 Text einlesen (Lange Zeilen) 1.2 1.2 kein JIT 1.3 HotSpot 1.0 HotSpot 2nd Run 1.1.6 Unbuffered Inputstream 1951% 3567% 1684% 1610% 1641% 1341% Buffered Inputstream 100% 450% 52% 56% 45% 174% 8K Buffered Inputstream 102% 477% 50% 45% 48% 225% Buffered Reader 47% 409% 43% 74% 41% 43% Custom-built Reader 26% 351% 37% 81% 36% 15% Custom reader and converter 12% 69% 18% 77% 17% 10% Bernhard Mähr Java Performance Tuning 23/25 Text einlesen (Kurze Zeilen) 1.2 1.2 kein JIT 1.3 HotSpot 1.0 HotSpot 2nd Run 1.1.6 Unbuffered Inputstream 1308% 2003% 1101% 1326% 1232% 871% Buffered Inputstream 100% 363% 33% 50% 54% 160% 8K Buffered Inputstream 101% 367% 31% 41% 54% 231% Buffered Reader 111% 554% 39% 149% 45% 127% 19% 237% 28% 94% 26% 14% 9% 56% 21% 80% 53% 8% Custom-built Reader Custom reader and converter Bernhard Mähr Java Performance Tuning 24/25 Quellen Bernhard Mähr Jack Shirazi: Java Performance Tuning ab Feb 2003 neue stark erweiterte Auflage http://www.javaperformancetuning.com/ http://www2.cs.cmu.edu/~jch/java/optimization.html Java Performance Tuning 25/25