7. Performance und Speicherauslastung • • • • • Java-Parameter mit Performance-Einfluss Versteckte Speicherlecks Direkte Zeitmessung in Java Konzept von Performance-Messwerkzeugen Netbeans-Profiler Software-Qualität Stephan Kleuker 232 Typische Probleme • Programme zur Zeit- und Speichermessung beeinflussen Laufzeit und verbrauchten Speicher • Gerade bei Laufzeitbetrachtungen können durch langsamere Abläufe neue Effekte entstehen • Testszenario muss in realistischer Zeit messbar sein • generell sollten auf Testrechner wenig oder einfach bzgl. Speicher- und Rechenzeitverbrauch zu kalkulierende Programme laufen • oftmals ist mehrmalige Messwiederholung sinnvoll • bei Nutzung von Zufallswerten muss man Werte entweder speichern oder Versuche häufig wiederholen • Java VM kann recht flexibel bzgl. Speicher gestartet werden; entspricht ggfls. Optimierungsaufgabe für Applikation • man kann Strategie für Java VM Garbage Collector ändern Software-Qualität Stephan Kleuker 233 Parameter von java mit Performance-Einfluss • Direkte Parameter für die Java VM -Xbatch Disable background compilation. -Xdebug Start with the debugger enabled. -Xnoclassgc Disable class garbage collection. -Xincgc Enable the incremental garbage collector. -Xmsn Specify the initial size, in bytes, of the memory allocation pool. (-Xms6144k -Xms6m) -Xmxn Specify the maximum size, in bytes, of the memory allocation pool. (-Xmx81920k -Xmx80m) -Xssn Set thread stack size. http://download.oracle.com/javase/6/docs/technotes/tools/w indows/java.html Software-Qualität Stephan Kleuker 234 Parameter von javac mit Performance-Einfluss • Direkte Parameter für den Java-Compiler -g Generate all debugging information, including local variables. -verbose Verbose output. This includes information about each class loaded and each source file compiled. -target version Generate class files that target a specified version of the VM. (1.1 1.2 1.3 1.4 1.5 (also 5) and 1.6 (also 6)) -Xlint Enable all recommended warnings. (Passt hier nicht hin, ist aber wichtig für QS ☺) • http://download.oracle.com/javase/6/docs/technotes/tools /windows/javac.html Software-Qualität Stephan Kleuker 235 Verstecktes Speicherleck (1/3) package boese; import import import import import java.io.File; java.io.FileWriter; java.io.IOException; java.util.ArrayList; java.util.List; public class MachAuf { public List<FileWriter> fwl = new ArrayList<FileWriter>(); public void steuern() throws IOException { int anzahl = 0; while (anzahl != 42) { System.out.print("Anzahl: "); anzahl = Eingabe.leseInt(); System.out.print("Datei: "); oeffnen(Eingabe.leseString(), anzahl); } Stephan Kleuker } Software-Qualität 236 Verstecktes Speicherleck (2/3) public void oeffnen(String name, int anzahl) throws IOException { for (int i = 0; i < anzahl; i++){ FileWriter fw= new FileWriter( new File(".\\bah\\"+name + i + ".dof")); fw.write(42); fwl.add(fw); } } public static void main(String[] arg) throws IOException { new MachAuf().steuern(); } } Software-Qualität Stephan Kleuker 237 Verstecktes Speicherleck (3/3) Programmstart Software-Qualität Stephan Kleuker 238 Java hat eigenen Profiler • Option der JavaVM -Xprof (Ausgabe wird auch von Werkzeugen genutzt) Software-Qualität Stephan Kleuker 239 Zeitmessung selbst gestrickt (1/6) • Szenario: Abteilung mit mehreren Projekten, Projekte mit mehreren Mitarbeitern • Frage nach passenden Typ für projekte, mitarbeiter Software-Qualität Stephan Kleuker 240 Zeitmessung selbst gestrickt (2/6) - Ausschnitte public class Abteilung extends Orgeinheit { // hier verschiedene Set-Implementierungen testbar // analog auch in Projekt private Set<Projekt> projekte = new HashSet<Projekt>(); public List<String> mitarbeiterInProjekten(int nr){ List<String> ergebnis = new ArrayList<String>(); for(Projekt p:projekte) if(p.suchenBeiNr(nr)!=null) ergebnis.add(p.getName()); return ergebnis; } // ... } Software-Qualität Stephan Kleuker 241 Zeitmessung selbst gestrickt (3/6) - Ausschnitte public class Projekt extends Orgeinheit{ private Set<Mitarbeiter> mitarbeiter = new HashSet<Mitarbeiter>(); public Mitarbeiter suchenBeiNr(int nr){ for(Mitarbeiter m:mitarbeiter) if(m.getNr()==nr) return m; return null; } public class Mitarbeiter extends Orgeinheit { ... } Software-Qualität Stephan Kleuker 242 Zeitmessung selbst gestrickt (4/6) - Testszenario public Lastdaten() { int anzahl=10000; long vorher = System.currentTimeMillis(); long summe = 0; long gestoppt; List<Mitarbeiter> m = new ArrayList<Mitarbeiter>(); List<Projekt> p = new ArrayList<Projekt>(); List<Abteilung> a = new ArrayList<Abteilung>(); for (int i = 0; i < anzahl; i++) m.add(new Mitarbeiter(new Date().toString())); for (int i = 0; i < anzahl/10; i++) { Projekt pr = new Projekt(new Date().toString()); for (int j = 0; j < anzahl/100; j++) pr.mitarbeiterHinzu(m.get((int) (m.size()* Math.random()))); p.add(pr); } for (int i = 0; i < anzahl/100; i++) { Abteilung ab = new Abteilung(new Date().toString()); for (int j = 0; j < anzahl/1000; j++) ab.projektHinzu(p.get((int) (p.size() * Math.random()))); a.add(ab); } Software-Qualität Stephan Kleuker 243 Zeitmessung selbst gestrickt (5/6) - Testszenario gestoppt=System.currentTimeMillis(); summe +=(gestoppt-vorher); System.out.println("verbraucht erstellen: "+(gestoppt - vorher)); vorher = System.currentTimeMillis(); for(int i=0;i<anzahl;i++) for(Abteilung ab:a) ab.mitarbeiterInProjekten(i); gestoppt=System.currentTimeMillis(); summe +=(gestoppt-vorher); System.out.println("verbraucht auslesen: "+(gestoppt - vorher)); vorher = System.currentTimeMillis(); for(int i=0;i<anzahl;i++) for(Abteilung ab:a) ab.mitarbeiterEntfernen(i); gestoppt=System.currentTimeMillis(); summe +=(gestoppt-vorher); System.out.println("verbraucht loeschen: "+(gestoppt - vorher)); System.out.println("gesamt verbraucht: " + summe); } Software-Qualität Stephan Kleuker 244 Zeitmessung selbst gestrickt (6/6) - Ergebnisse Klasse HashSet LinkedHashSet CopyOnWriteArraySet erstellen auslesen löschen 170 174 181 180 230 224 37088 36925 26444 24870 15396 15253 23664 23503 14161 13478 14252 14033 gesamt 60922 60602 40786 38528 29878 29510 private Set<Projekt> projekte = new Klasse<Projekt>(); private Set<Mitarbeiter> mitarbeiter = new Klasse<Mitarbeiter>(); Software-Qualität Stephan Kleuker 245 Variante (1/2) • Objekte werden sortierbar: public class Orgeinheit implements Comparable<Orgeinheit>{ @Override public int compareTo(Orgeinheit o) { return nr-o.nr; } ... • statt in Projekt: public void mitarbeiterLoeschen(int nr){ mas.remove(suchenBeiNr(nr)); } • neu in Projekt: public void mitarbeiterLoeschen(int nr){ Mitarbeiter m = suchenBeiNr(nr); if(m!=null) mitarbeiter.remove(m); } Software-Qualität Stephan Kleuker 246 Variante (2/2) Klasse HashSet LinkedHashSet CopyOnWriteArraySet ConcurrentSkipListSet TreeSet Software-Qualität erstellen auslesen löschen 159 143 151 150 210 209 187 177 168 162 37202 36965 25944 25600 15482 15589 30882 32112 39322 37908 Stephan Kleuker 23375 23187 13981 13662 8263 8253 15999 17194 20320 19453 gesamt 60736 60295 40076 39412 23955 24051 47068 49483 59720 57523 247 Konzept von Performance-Messwerkzeugen • ähnlich zum letzten Beispiel wird Java-Code erweitert • java -agentlib:hprof (hprof als Beispiel) • Erweiterungen melden Informationen an Messerwerkzeug, welches protokolliert • Meldungen sollen erlauben, das Verhalten des Messwerkzeugs heraus zu rechnen, genauer: – Java hat Java Virtual Machine Tool Interface (JVMTI) – ermöglicht als Aufrufargument einen Java Agent – Java Agent ist spezielle Klasse • aufgerufen bevor irgendwas passiert (vor main) • Java Agent kann Filter installieren; bekommt mit, wenn Klassen geladen werden und kann diese verändern • http://java.sun.com/developer/technicalArticles/J2SE/jvm_ti/ • (Ansatz vergleichbar mit Aspect-opriented Programming) Software-Qualität Stephan Kleuker 248 Beispiel: Netbeans Profiler (1/7) Software-Qualität Stephan Kleuker 249 Beispiel: Netbeans Profiler (2/7) Software-Qualität Stephan Kleuker 250 Beispiel: Netbeans Profiler (3/7) Software-Qualität Stephan Kleuker 251 Beispiel: Netbeans Profiler (4/7) Klasse Hinzu InProjekten Entfernen gesamt HashSet 133 46486 40577 88379 LinkedHashSet 128 38473 34285 74088 CopyOnWriteArraySet 3468 23752 24671 53088 ConcurrentSkipListSet 1617 48149 40914 91983 TreeSet 888 48805 39259 90200 • Vorletzten beiden Klassen sind thread-safe; dies kann Unterschied zu erster Messung erklären • TreeSet, ConcurrentSkipListSet benötigten Comparable<T> • Wieder: HashSet wie TreeSet; LinkedHashSet besser • Test war mit kleinen Objekten (Einfluss?) Software-Qualität Stephan Kleuker 252 Beispiel: Netbeans Profiler (5/7) Software-Qualität Stephan Kleuker 253 Beispiel: Netbeans Profiler (6/7) Software-Qualität Stephan Kleuker 254 Beispiel: Netbeans Profiler (7/7) Klasse Top 3 Speicherverbrauch HashSet LinkedHashSet CopyOnWriteArraySet ConcurrentSkipListSet TreeSet Software-Qualität Stephan Kleuker 255 Zusammenfassung • Definition des Testszenarios ist hier sehr komplexe Aufgabe • Testergebnisse können von vielen kleinen Parametern (Objektgrößen, Systemeinstellungen) abhängen • Kleine Änderungen können große Effekte haben • Performance- und Speicherverbrauchsmessung oft nicht ganz exakt durchführbar • Zentrale Frage: welche Methode wird wie of aufgerufen und verbraucht wieviel Zeit • Zentrale Frage: Welche Onjekte verbrauchen wieviel Speicherplatz • Werkzeugunterstützung ist vorhanden Software-Qualität Stephan Kleuker 256