Folien

Werbung
Effiziente Java Programmierung
Seminar „Implementierung moderner virtueller Maschinen am
Beispiel von Java“ SS 2009
von
Reinhard Klaus Losse
20. Mai 2009
Gliederung
●
Definition Effizienz
●
Werkzeuge zum Messen von Effizienz
●
Beispiel aus der Praxis
●
Mögliche Bösewichte
●
Tests
2
1. Definition Effizienz
●
Ein Programm ist effizient, wenn:
●
seine Rechengeschwindigkeit niedrig ist,
●
sein Speicherverbrauch niedrig ist und
●
●
die Geschwindigkeit von Ein-/ Ausgabeoperationen
niedrig ist.
hier: Effizienz auf der Ebene der JVM und des
Bytecodes
3
2. Messwerkzeuge
●
●
●
●
Windows-Task-Manager
äquivalente Tools in Unix/ Linux: top, ps,
netstat, vmstat, iostat, sar (System Accounting
Reports), truss, strace
Profiler, z. B. Hprof
Methoden java.lang.System.currentTimeMillis()
und java.lang.System.nanoTime() (seit Java 5)
4
Profiler: Motivation
●
geben z. B. Auskunft darüber:
●
wie viele Objekte vom Typ X existieren,
●
wie viel Speicher sie verbrauchen,
●
wie Zeit ein Programm in Methode y verbringt und
●
wie häufig diese Methode aufgerufen wurde
5
Geschichte von Hprof
●
●
war in den Java-Versionen 1.2 bis 5 als Teil des
experimentellen Java Virtual Machine Profiler
Interface (JVMPI) enthalten
wurde in Java 5 auf dem neuen Java Virtual
Machine Tool Interface (JVM TI) implementiert,
das das JVMPI ersetzte
6
Aufruf von Hprof
●
bis Java 5:
●
●
ab Java 5:
●
●
java -Xrunhprof[:options] ToBeProfiledClass
java -agentlib:hprof[=options] ToBeProfiledClass
Liste aller Optionen:
●
java -agentlib:hprof=help
7
Aufruf von Hprof
●
●
Hprof speichert die Ergebnisse des Profilings in
eine Datei
jede Datei enthält:
●
Liste aller Threads
●
Liste von nummerierten Stacktraces
8
Aufruf von Hprof
●
jede Datei kann darüber hinaus enthalten:
●
●
●
●
Heap-Dump
Liste aller Objekttypen geordnet nach dem
Speicherverbrauch (Sites)
Liste aller Methoden geordnet nach zeitlichen
Stichproben (CPU Samples)
Liste aller Methoden geordnet nach dem
Zeitverbrauch (CPU Time)
9
Beispiel aus der Praxis
●
String-Variante
String halloWelt = “Hallo Welt “;
String weite = “weite “;
String hallo = halloWelt.substring(0, 7);
String welt = halloWelt.substring(7);
String halloWeiteWelt = hallo.concat(weite).concat(welt);
●
4 Objekte
10
3. Beispiel aus der Praxis
●
StringBuffer-Variante
String halloWelt = “Hallo Welt “;
String weite = “weite “;
StringBuffer stringBuffer = new StringBuffer(halloWelt);
stringBuffer.insert(7, weite);
String halloWeiteWelt = stringBuffer.toString();
●
3 Objekte
11
Beispiel aus der Praxis
●
String-Variante mit +
String halloWelt = “Hallo Welt “;
String weite = “weite “;
String hallo = halloWelt.substring(0, 7);
String welt = halloWelt.substring(7);
String halloWeiteWelt = hallo + weite + welt;
●
4 Objekte
12
Beispiel aus der Praxis
●
●
Messergebnisse:
●
String:
6628217 ns
100%
●
StringBuffer:
7568280 ns
114%
●
String mit +:
9880585 ns
149%
Einfügen von Strings erfolgt in Bezug auf den
Zeitbedarf am besten mit der Klasse String
13
4. Mögliche Bösewichte
●
Objekt mit vielen Instanzenvariablen
●
Arrays mit vielen Elementen
●
viele Methodenaufrufe
●
häufige Arrayzugriffe
●
häufige Feldzugriffe
14
Schleifen
●
for (int i = 0; i < list.size(); i++) {
Object o = list.get(i);
...
}
●
for (int i = 0, n=list.size(); i < n; i++) {
Object o = list.get(i);
...
}
15
Arrays
●
private int arrayAccessInLoop() {
int[] array = new int[1];
for (int i=0; i < 20000000; i++) array[0] += i;
return array[0];
}
16
5. Tests
●
●
Testsystem:
●
Windows XP
●
1 GB Arbeitsspeicher
●
Pentium M 1,86 Ghz
●
Java 6
Durchführung der Tests
●
1.000-fache Messung der Zeit über nanoTime()
17
Objekt- und Arrayerzeugung
●
●
Erzeugung eines Objekts mit nur einer intInstanzenvariable
Erzeugung eines Objekts mit 18
Instanzenvariablen, 9 int-Variablen und 9
String-Variablen
●
Erzeugung eines Arrays mit 0 Elementen
●
Erzeugung eines Arrays mit 5 Elementen
18
Objekt- und Arrayerzeugung
●
Messergebnisse:
●
Objekt mit wenigen Elementen:
1955 ns
100%
●
Objekt mit vielen Elementen:
2793 ns
143%
●
Array mit 0 Elementen:
1676 ns
100%
●
Array mit 5 Elementen:
1955 ns
117%
19
Methodenaufrufe
●
100.000-facher Aufrufe folgender Methode:
<Modifier> int myMethod(int j) {
return j+1;
}
●
Modifier:
●
public
●
public static
●
private
●
private static
20
Methodenaufrufe
●
●
Interface:
●
Klasse implementiert ein Interface
●
Interface enthält die Methode myMethod
Oberklasse:
●
Klasse erbt von Oberklasse
●
1. Variante: Klasse überschreibt myMethod
●
●
2. Variante: Klasse implementiert die abstrakte
Methode myMethod
100.000-facher Aufruf der Methode myMethod
21
Methodenaufrufe
●
letzte Variante: inline
●
●
for (int i = 0; i < 100000; i++) j = j + 1;
direkte Ausführung der Operation statt
Methodenaufruf
22
Methodenaufrufe
●
Messergebnisse mit inline:
●
public:
15029284 ns
279%
●
public static:
13376281 ns
249%
●
private:
19297983 ns
359%
●
private static:
13376281 ns
249%
●
abstrakt:
19432637 ns
361%
●
überschreiben: 15029284 ns
279%
●
Interface:
18030224 ns
335%
●
inline:
5377499 ns
100%
23
Methodenaufrufe
●
Messergebnisse ohne inline:
●
public:
15029284 ns
112%
●
public static:
13376281 ns
100%
●
private:
19297983 ns
144%
●
private static:
13376281 ns
100%
●
abstrakt:
19432637 ns
145%
●
überschreiben: 15029284 ns
112%
●
Interface:
135%
18030224 ns
24
Array- und Feldzugriff
●
Zugriff auf das Arrayelement Nr. 10:
int[] array = new int[100];
int j = 0;
array[10] = 1;
for (int i = 0; i < 100000; i++)
j = j + array[10];
25
Array- und Feldzugriff
●
●
100.000-facher Zugriff auf ein Feld einer
anderen Klasse:
●
public
●
public static
100.000-facher Zugriff auf eine lokale Variable
26
Array- und Feldzugriff
●
Messergebnisse:
●
Arrayzugriff:
6403607 ns
100%
●
Feldzugriff (public):
6857296 ns
107%
●
Feldzugriff (public static):
6469537 ns
101%
●
Feldzugriff (lokal):
6858413 ns
107%
27
Fazit
●
●
●
●
●
Erzeugung größerer Objekte und Arrays dauert
länger als die kleinerer
inline bei Methodenaufrufen mit Abstand am
schnellsten, gefolgt von statischen
Methodenaufrufen
private und abstrakt bei Methodenaufrufen am
langsamsten, gefolgt von Interface
Arrayzugriffe und statische Feldzugriff schneller
als sonstige Feldzugriffe
aber: JIT-Compiler bringt alles durcheinander
28
Quellen
●
●
●
Performant Java programmieren, Hendrik Schreiber, Addison Wesley 2002
HPROF: A Heap/CPU Profiling Tool in J2SE 5.0,
http://java.sun.com/developer/technicalArticles/Programming/HPROF.html, abgerufen am
22.04.2009
JDK 6 Documentation
29
Herunterladen