250 likes | 491 Views
Java Performance Tuning. Performance Tuning is similar to playing a strategy game but happily you usually get paid for it. Schlechte Performanz kaschieren. Eigentlich kein Tuning Benutzer findet das Programm schnell Responsabiltiy Trennung von UI und Arbeits-Thread
E N D
Java Performance Tuning Performance Tuning is similar to playing a strategy game but happily you usually get paid for it.
Schlechte Performanz kaschieren • 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
Allgemeines • 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
Schritte • 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
Bottelneck auswählen • 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
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 Java Performance Tuning
Inlineing final, private und static Methoden können eingefügt werden. Geschieht meist nur wenn keine lokalen Variablen verwendet werden • private int m1() { return 5; }private int m2() { return m1(); } • 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
Optimierungen in Standardanweisungen • 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){//lieberif (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
Canonicalization • 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);System.out.println(t1==Boolean.TRUE); //falseSystem.out.println(t1.equals(Boolean.TRUE)); //true Boolean.TRUE; Java Performance Tuning
Objekte • 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
Initialisieren vs Clonen • 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
Wiederverwenden von Parameter-Objekten • 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
Wiederverwenden von Parameter-Objekten • 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
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 count=countArr[0];int addpoints=5*points; for(int i=collection.size(); --i>=0; ){ count+=addpoints;}countArr[0]=count; int addpoints = points; for(long i=0; i<collection.size()*50000; i++) { countArr[0]=countArr[0] + 5 * addpoints; } Laufzeit 1.3.1 Code / 1.1.8 No JIT: 228,559 s / 1111% Laufzeit 1.3.1 Code / 1.1.8: 3,305 s / 16% Laufzeit 1.4.1 Code / 1.4.1 Client: 36,813 s / 155% Laufzeit 1.4.1 Code / 1.4.1 Server: 25,046 s / 122% int addpoints = points; int iter = collection.size()*50000; for(long i=0; i<iter; i++) { countArr[0]=countArr[0] + 5 * addpoints; } Laufzeit 1.3.1 Code / 1.1.8 No JIT: 128,505 s / 624% Laufzeit 1.3.1 Code / 1.1.8: 3,305 s / 16% Laufzeit 1.4.1 Code / 1.4.1 Client: 14,591 s / 71% Laufzeit 1.4.1 Code / 1.4.1 Server: 4,136 s / 20% int addpoints = points * 5; int iter = collection.size()*50000; int count = countArr[0]; for(long i=0; i<iter; i++) { count=count + addpoints; } countArr[0] = count; Laufzeit 1.3.1 Code / 1.1.8 No JIT: 98,862 s / 480% Laufzeit 1.3.1 Code / 1.1.8: 3,705 s / 18% Laufzeit 1.4.1 Code / 1.4.1 Client: 11,897 s / 58% Laufzeit 1.4.1 Code / 1.4.1 Server: 4,116 s/ 20% int addpoints = points * 5; int iter = collection.size()*50000; int count = countArr[0]; for(int i=0; i<iter; i++) { count=count + addpoints; } countArr[0] = count; Laufzeit 1.3.1 Code / 1.1.8 No JIT: 44,384 s / 216% Laufzeit 1.3.1 Code / 1.1.8: 1,533 s / 7% Laufzeit 1.4.1 Code / 1.4.1 Client: 6,900 s / 34% Laufzeit 1.4.1 Code / 1.4.1 Server: 0,701 s / 3% int addpoints=5*points; int count=countArr[0]; for(int i=collection.size()*50000; --i>=0; ){ count+=addpoints; } countArr[0]=count; Laufzeit 1.3.1 Code / 1.1.8 No JIT: 41,610 s / 202% Laufzeit 1.3.1 Code / 1.1.8: 1,513 s / 7% Laufzeit 1.4.1 Code / 1.4.1 Client: 7,651 s / 37% Laufzeit 1.4.1 Code / 1.4.1 Server: 0,711 s / 3% int count=countArr[0]; int addpoints=5*points; int i=collection.size()*50000; for(; --i>=0; ){ count+=addpoints; } countArr[0]=count; Laufzeit 1.3.1 Code / 1.1.8 No JIT: 39,997 s / 194% Laufzeit 1.3.1 Code / 1.1.8: 1,512 s / 7% Laufzeit 1.4.1 Code / 1.4.1 Client: 7,691 s / 37% Laufzeit 1.4.1 Code / 1.4.1 Server: 0,711 s / 3% for(long i=0; i<collection.size()*50000; i++) { countArr[0]=countArr[0] + 5 * points; } Laufzeit 1.3.1 Code / 1.1.8 No JIT: 225,844 s / 1097% Laufzeit 1.3.1 Code / 1.1.8: 2,864 s / 14% Laufzeit 1.4.1 Code / 1.4.1 Client: 31,845 s / 155% Laufzeit 1.4.1 Code / 1.4.1 Server: 20,580 s / 100% int addpoints = points * 5; int iter = collection.size()*50000; for(long i=0; i<iter; i++) { countArr[0]=countArr[0] + addpoints; } Laufzeit 1.3.1 Code / 1.1.8 No JIT: 146,100 s / 710% Laufzeit 1.3.1 Code / 1.1.8: 3,505 s / 17% Laufzeit 1.4.1 Code / 1.4.1 Client: 14,331 s / 70% Laufzeit 1.4.1 Code / 1.4.1 Server: 4,136 s/ 20% int addpoints = points * 5; int iter = collection.size()*50000; int count = countArr[0]; for(int i=0; i<iter; i++) { count+= addpoints; } countArr[0] = count; Laufzeit 1.3.1 Code / 1.1.8 No JIT: 44,474 s / 216% Laufzeit 1.3.1 Code / 1.1.8: 1,602 s / 8% Laufzeit 1.4.1 Code / 1.4.1 Client: 6,980 s / 34% Laufzeit 1.4.1 Code / 1.4.1 Server: 0,701 s / 3% int addpoints = points * 5; int iter = collection.size()*50000; int count = countArr[0]; for(int i=iter; --i>=0;) { count+= addpoints; } countArr[0] = count; Laufzeit 1.3.1 Code / 1.1.8 No JIT: 40,769 s / 198% Laufzeit 1.3.1 Code / 1.1.8: 1,602 s / 8% Laufzeit 1.4.1 Code / 1.4.1 Client: 6,229 s / 30% Laufzeit 1.4.1 Code / 1.4.1 Server: 0,701 s / 3% Java Performance Tuning
Schleifen / Exceptions • 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
Rekursionen • 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
Laden beschleunigen • Spash-Screen • Unkompremierte JAR-Archive • Preload von Klassen (Achtung: Caching der VM nicht behindern) • Lazy-Initialisation Java Performance Tuning
String / StringBuffer • 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
Threads/Synchronized • 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
Syncronized Wrappers für eigene Klassen • 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
Collections Java Performance Tuning
Selber implementieren? • 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
Text einlesen (Lange Zeilen) Java Performance Tuning
Text einlesen (Kurze Zeilen) Java Performance Tuning
Quellen • Jack Shirazi: Java Performance Tuningab Feb 2003 neue stark erweiterte Auflage • http://www.javaperformancetuning.com/ • http://www-2.cs.cmu.edu/~jch/java/optimization.html Java Performance Tuning