summaryrefslogtreecommitdiffstats
path: root/Master/Reference Architectures and Patterns/hjp5/html/k100315.html
diff options
context:
space:
mode:
authorSven Eisenhauer <sven@sven-eisenhauer.net>2023-11-10 15:11:48 +0100
committerSven Eisenhauer <sven@sven-eisenhauer.net>2023-11-10 15:11:48 +0100
commit33613a85afc4b1481367fbe92a17ee59c240250b (patch)
tree670b842326116b376b505ec2263878912fca97e2 /Master/Reference Architectures and Patterns/hjp5/html/k100315.html
downloadStudium-master.tar.gz
Studium-master.tar.bz2
add new repoHEADmaster
Diffstat (limited to 'Master/Reference Architectures and Patterns/hjp5/html/k100315.html')
-rw-r--r--Master/Reference Architectures and Patterns/hjp5/html/k100315.html750
1 files changed, 750 insertions, 0 deletions
diff --git a/Master/Reference Architectures and Patterns/hjp5/html/k100315.html b/Master/Reference Architectures and Patterns/hjp5/html/k100315.html
new file mode 100644
index 0000000..704f7ff
--- /dev/null
+++ b/Master/Reference Architectures and Patterns/hjp5/html/k100315.html
@@ -0,0 +1,750 @@
+<html>
+<head>
+<title>
+Handbuch der Java-Programmierung, 5. Auflage
+</title>
+</head>
+<body>
+<a name="startofbody"></a>
+<script language="JavaScript" src="hjp4lib.js">
+</script>
+<script language="JavaScript">
+installKbdHandler("97,#startofbody;101,#endofbody;116,cover.html;122,k100003.html;115,search.html;105,index.html;100,JDKDOCS;112,APIDOCS;104,k100312.html;106,k100314.html;107,k100316.html;108,k100317.html");
+</script>
+<table border=0 cellpadding=0 cellspacing=1 width="100%">
+<tr bgcolor="#EEFFCC">
+<td width="7%" align=center bgcolor="#DDCC99"><a href="cover.html">&nbsp;Titel&nbsp;</a>
+<td width="7%" align=center bgcolor="#DDCC99"><a href="k100003.html">&nbsp;Inhalt&nbsp;</a>
+<td width="7%" align=center bgcolor="#DDCC99"><a href="search.html">&nbsp;Suchen&nbsp;</a>
+<td width="7%" align=center bgcolor="#DDCC99"><a href="index.html">&nbsp;Index&nbsp;</a>
+<td width="7%" align=center bgcolor="#DDCC99"><a href="../jdkdocs/index.html" onClick="this.href=getDocIndex()">&nbsp;DOC&nbsp;</a>
+<td align="right">Handbuch der Java-Programmierung, 5. Auflage
+<tr bgcolor="#EEFFCC">
+<td width="7%" align=center bgcolor="#DDCC99"><a href="k100312.html">&nbsp;&lt;&lt;&nbsp;</a>
+<td width="7%" align=center bgcolor="#DDCC99"><a href="k100314.html">&nbsp;&nbsp;&lt;&nbsp;&nbsp;</a>
+<td width="7%" align=center bgcolor="#DDCC99"><a href="k100316.html">&nbsp;&nbsp;&gt;&nbsp;&nbsp;</a>
+<td width="7%" align=center bgcolor="#DDCC99"><a href="k100317.html">&nbsp;&gt;&gt;&nbsp;</a>
+<td width="7%" align=center bgcolor="#DDCC99"><a href="../jdkdocs/api/index.html" onClick="this.href=getApiIndex()">&nbsp;API&nbsp;</a>
+<td align="right">Kapitel 50 - Performance-Tuning
+</table>
+<hr>
+
+
+<!-- Section -->
+<a name="profilereinsatz"></a>
+<h2>50.3 Einsatz eines Profilers </h2>
+<hr>
+<ul>
+<li><a href="k100315.html#profilereinsatz">50.3 Einsatz eines Profilers</a>
+<ul>
+<li><a href="k100315.html#sectlevel3id050003001">50.3.1 Grundlagen</a>
+<li><a href="k100315.html#sectlevel3id050003002">50.3.2 Eine Beispielsitzung mit dem Profiler</a>
+<ul>
+<li><a href="k100315.html#sectlevel4id050003002001">Erzeugen der Profiling-Informationen</a>
+<li><a href="k100315.html#sectlevel4id050003002002">Das CPU-Profile</a>
+<li><a href="k100315.html#sectlevel4id050003002003">Das Heap-Profile</a>
+<li><a href="k100315.html#sectlevel4id050003002004">Die optimierte Version des Programms</a>
+</ul>
+<li><a href="k100315.html#sectlevel3id050003003">50.3.3 Ausblick</a>
+</ul>
+</ul>
+<hr>
+
+
+<!-- Section -->
+<a name="sectlevel3id050003001"></a>
+<h3>50.3.1 Grundlagen </h3>
+
+<p>
+Die bisher vorgestellten Tipps und Tricks sind sicherlich eine Hilfe,
+um bereits w&auml;hrend der Entwicklung eines Programms grunds&auml;tzliche
+Performance-Probleme zu vermeiden. L&auml;uft das fertige Programm
+dann trotzdem nicht mit der gew&uuml;nschten Geschwindigkeit (was
+in der Praxis h&auml;ufig vorkommt), helfen pauschale Hinweise leider
+nicht weiter. Statt dessen gilt es herauszufinden, welche Teile des
+Programms f&uuml;r dessen schlechte Performance verantwortlich sind.
+Bei gr&ouml;&szlig;eren Programmen, die aus vielen tausend Zeilen
+Quellcode bestehen, ist das eine komplizierte Aufgabe, die nur mit
+Hilfe eines guten <a name="ixa103670"><i>Profilers</i></a> bew&auml;ltigt
+werden kann. Der Profiler ist ein Werkzeug, mit dessen Hilfe im laufenden
+Programm <i>Performanceparameter</i>, wie beispielsweise die verbrauchte
+CPU-Zeit, die Anzahl der allozierten Objekte oder die Anzahl der Aufrufe
+bestimmter Methoden, &uuml;berwacht und gemessen werden k&ouml;nnen.
+Durch manuelle Inspektion der erzeugten Logdateien oder mit Hilfe
+eines Auswertungsprogramms kann dann festgestellt werden, welche Teile
+des Programms die gr&ouml;&szlig;te Last erzeugen und daher verbesserungsbed&uuml;rftig
+sind.
+<p>
+<table border=0 cellspacing=0 cellpadding=0 width=100%>
+<tr>
+<td width=1 align=left valign=top bgcolor="#FF9900"><img src="trp1_1.gif"></td>
+<td><img src="trp1_1.gif" width=1></td>
+<td width=1 align=left valign=top bgcolor="#FF9900"><img src="trp1_1.gif"></td>
+<td><img src="trp1_1.gif" width=2></td>
+<td valign=top width=1000>
+
+<p>
+Das Standard-JDK enth&auml;lt bereits seit der Version 1.0 einen eingebauten
+Profiler, der Informationen &uuml;ber Laufzeit und Aufrufh&auml;ufigkeit
+von Methoden geben kann. Im JDK 1.2 wurde er erweitert und kann seither
+den Speicherverbrauch messen und Profiling-Informationen <i>threadweise</i>
+ausgeben. Mit dem JDK 1.3 wurde er erneut verbessert und mit einem
+offenen Profiler-API versehen (<a name="ixa103671"><i>JVMPI</i></a>,
+<a name="ixa103672"><i>Java Virtual Machine Profiler Interface</i></a>).
+Mit dessen Hilfe ist es m&ouml;glich, eigene Profiling-Werkzeuge zu
+schreiben. Fester Bestandteil des JDK ist eine Beispielimplementierung
+<a name="ixa103673"><a href="index_h.html#ixb102749"><font color=#000080><tt>hprof</tt></font></a></a>,
+die f&uuml;r einfache Profiling-Aufgaben verwendet werden kann.</td>
+<td><img src="trp1_1.gif" width=2></td>
+<td valign=top>
+<table border=0 cellspacing=0 cellpadding=1 width=100% bgcolor="#FF9900">
+<tr>
+<td><font color="#FFFFFF">&nbsp;JDK1.1-6.0&nbsp;</font></td>
+</tr>
+</table>
+</td>
+<td width=1 align=left valign=top bgcolor="#FF9900"><img src="trp1_1.gif"></td>
+</tr>
+</table>
+
+<p>
+Im Vergleich zu spezialisierten Produkten sind die F&auml;higkeiten
+des eingebauten Profilers etwas rudiment&auml;r. Insbesondere die
+vom Profiler erzeugte Ausgabedatei erfordert einigen Nachbearbeitungsaufwand.
+Zudem gibt es keine grafischen Auswertungen wie bei kommerziellen
+Profilern. Dennoch ist der JDK-Profiler ein brauchbares und hilfreiches
+Instrument, mit dem Performanceprobleme und Speicherengp&auml;sse
+analysiert werden k&ouml;nnen. Wir wollen uns in diesem Abschnitt
+mit den Grundlagen seiner Bedienung vertraut machen.
+
+<p>
+Als Beispiel f&uuml;r die Anwendung des Profiler wollen wir ein Programm
+verwenden, dessen simple Aufgabe darin besteht, einen <a href="index_s.html#ixb100117"><font color=#000080><tt>String</tt></font></a>
+mit 10000 Punkten zu erzeugen und auf dem Bildschirm auszugeben. Statt
+die Ratschl&auml;ge aus dem vorigen Abschnitt zu beherzigen, verwendet
+das Programm den Operator <font color="#000077"><tt>+=</tt></font>,
+um den <a href="index_s.html#ixb100117"><font color=#000080><tt>String</tt></font></a>
+zeichenweise in einer Schleife zusammenzusetzen. Auf langsameren Rechnern
+kann es durchaus einige Sekunden dauern, bis der String erzeugt und
+vollst&auml;ndig auf dem Bildschirm ausgegeben wurde:
+<a name="listingid050009"></a>
+
+<p>
+<table border=0 cellspacing=0 cellpadding=0 width=100% bgcolor="#DDDDDD">
+<tr>
+<td valign=top>
+<font color="#000055">
+<pre>
+<font color="#555555">001 </font><font color="#00AA00">/* ProfTest1A.java */</font>
+<font color="#555555">002 </font>
+<font color="#555555">003 </font><font color="#0000AA">import</font> java.util.*;
+<font color="#555555">004 </font>
+<font color="#555555">005 </font><font color="#0000AA">public</font> <font color="#0000AA">class</font> ProfTest1A
+<font color="#555555">006 </font>{
+<font color="#555555">007 </font> <font color="#0000AA">public</font> <font color="#0000AA">static</font> String dots(<font color="#006699">int</font> len)
+<font color="#555555">008 </font> {
+<font color="#555555">009 </font> String ret = <font color="#0000FF">""</font>;
+<font color="#555555">010 </font> <font color="#0000AA">for</font> (<font color="#006699">int</font> i = 0; i &lt; len; ++i) {
+<font color="#555555">011 </font> ret += <font color="#0000FF">"."</font>;
+<font color="#555555">012 </font> }
+<font color="#555555">013 </font> <font color="#0000AA">return</font> ret;
+<font color="#555555">014 </font> }
+<font color="#555555">015 </font>
+<font color="#555555">016 </font> <font color="#0000AA">public</font> <font color="#0000AA">static</font> <font color="#006699">void</font> main(String[] args)
+<font color="#555555">017 </font> {
+<font color="#555555">018 </font> String s = dots(10000);
+<font color="#555555">019 </font> System.out.println(s);
+<font color="#555555">020 </font> }
+<font color="#555555">021 </font>}</pre>
+</font>
+</td>
+<td valign=top align=right>
+<a href="../examples/ProfTest1A.java"><font color="#000055" size=-1>ProfTest1A.java</font></a></td>
+</tr>
+</table>
+<i>
+Listing 50.9: Ein Beispielprogramm zum Testen des Profilers</i></p>
+
+<p>
+Nachfolgend wollen wir uns eine Beispielsitzung mit dem Profiler ansehen.
+&Auml;hnlich wie bei einem Debugger besteht die typische Vorgehensweise
+darin, schrittweise Informationen &uuml;ber Rechenzeit- und Speicherverbrauch
+zu gewinnen und das Programm mit diesen Informationen nach und nach
+zu optimieren. F&uuml;r gew&ouml;hnlich gibt es dabei kein Patentrezept,
+das direkt zum Erfolg f&uuml;hrt. Statt dessen &auml;hnelt der Umgang
+mit dem Profiler einer Detektivarbeit, bei der die einzelnen Teile
+der L&ouml;sung nach und nach gefunden werden.
+
+<!-- Section -->
+
+<a name="sectlevel3id050003002"></a>
+<h3>50.3.2 Eine Beispielsitzung mit dem Profiler </h3>
+
+
+<!-- Section -->
+<a name="sectlevel4id050003002001"></a>
+<h4>Erzeugen der Profiling-Informationen </h4>
+
+<p>
+Zun&auml;chst muss das Programm wie gew&ouml;hnlich &uuml;bersetzt
+werden:
+<font color="#333300">
+<pre>
+javac ProfTest1A.java
+</pre>
+</font>
+
+<p>
+Um das Programm unter Kontrolle des Profilers zu starten, ist die
+Option <a name="ixa103674"><a href="index_0.html#ixb102750"><font color=#000080><tt>-Xrunhprof</tt></font></a></a>
+zu verwenden und nach einem Doppelpunkt mit den erforderlichen Parametrisierungen
+zu versehen. Die Parameter werden als kommaseparierte Liste von Argumenten
+der Form &#187;Name=Wert&#171; angegeben. Die wichtigsten Parameter
+von <a href="index_h.html#ixb102749"><font color=#000080><tt>hprof</tt></font></a>
+sind: <a name="tableid050002"></a>
+
+<p>
+<table cols=2 border width=66%>
+
+<tr>
+<td valign=top align=left width=25%><b>Name</b></td>
+<td valign=top align=left width=75%><b>M&ouml;gliche Werte</b></td></tr>
+<tr>
+<td valign=top align=left>cpu</td>
+<td valign=top align=left>samples, times, old</td></tr>
+<tr>
+<td valign=top align=left>heap</td>
+<td valign=top align=left>dump, sites, all</td></tr>
+<tr>
+<td valign=top align=left>file</td>
+<td valign=top align=left>Name der Ausgabedatei</td></tr>
+<tr>
+<td valign=top align=left>depth</td>
+<td valign=top align=left>Maximale Tiefe der Stacktraces</td></tr>
+</table>
+<p><i>
+Tabelle 50.2: Parameter von hprof</i></p>
+
+<p>
+Mit der Option <font color="#000077"><tt>cpu</tt></font> wird der
+CPU-Profiler aktiviert. Er kennt die Modi &#187;samples&#171;, &#187;times&#171;
+und &#187;old&#171;. Im Modus &#187;samples&#171; werden die Profiling-Informationen
+dadurch gewonnen, dass das laufende Programm mit Hilfe eines separaten
+Threads regelm&auml;&szlig;ig unterbrochen wird. Bei jeder Unterbrechung
+wird ein Stacktrace gezogen, der dem Profiler Auskunft dar&uuml;ber
+gibt, welche Methode gerade ausgef&uuml;hrt wird, in welcher Quelltextzeile
+das Programm steht und wie die Kette ihrer Aufrufer aussieht. Jeder
+derartige Schnappschu&szlig; wird als <i>Sample</i> bezeichnet.
+
+<p>
+Die unterschiedlichen Stacktraces werden mit einem Aufrufz&auml;hler
+versehen, der immer dann um 1 erh&ouml;ht wird, wenn bei einer Unterbrechung
+ein entsprechender Stacktrace gefunden wird. Aus dem Endwert der Z&auml;hler
+kann dann abgeleitet werden, wo das Programm die meiste Rechenzeit
+verbraucht hat. Denn je h&ouml;her der Z&auml;hler war, desto &ouml;fter
+wurde das Programm an der zugeh&ouml;rigen Programmstelle &#187;angetroffen&#171;
+und desto wahrscheinlicher ist es, dass dort nennenswert Rechenzeit
+verbraucht wird.
+<p>
+<table border=0 cellspacing=0 cellpadding=0 width=100%>
+<tr>
+<td width=1 align=left valign=top bgcolor="#CC0000"><img src="trp1_1.gif"></td>
+<td><img src="trp1_1.gif" width=1></td>
+<td width=1 align=left valign=top bgcolor="#CC0000"><img src="trp1_1.gif"></td>
+<td><img src="trp1_1.gif" width=2></td>
+<td valign=top width=1000>
+
+<p>
+Nat&uuml;rlich ist diese Vorgehensweise nicht sehr pr&auml;zise, und
+es sind F&auml;lle denkbar, bei denen sie ganz versagt. Aber sie ist
+einfach zu implementieren und beeintr&auml;chtigt die Laufzeit des
+Programms nur unwesentlich. In der Praxis sollten die Ergebnisse mit
+der n&ouml;tigen Vorsicht betrachtet werden. Sie d&uuml;rfen nicht
+als absolute Me&szlig;werte angesehen werden, sondern sind vorwiegend
+dazu geeignet, Tendenzen zu erkennen und Programmteile mit besonders
+hoher Rechenzeit ausfindig zu machen.</td>
+<td><img src="trp1_1.gif" width=2></td>
+<td valign=top>
+<table border=0 cellspacing=0 cellpadding=1 width=100% bgcolor="#CC0000">
+<tr>
+<td><font color="#FFFFFF">&nbsp;Warnung&nbsp;</font></td>
+</tr>
+</table>
+</td>
+<td width=1 align=left valign=top bgcolor="#CC0000"><img src="trp1_1.gif"></td>
+</tr>
+</table>
+
+<p>
+Der zweite Modus &#187;times&#171; arbeitet etwas anders. Statt lediglich
+die Anzahl der Stacktraces zu z&auml;hlen, misst er tats&auml;chlich
+die innerhalb der einzelnen Methoden verbrauchte Rechenzeit. Allerdings
+wird dadurch auch die Laufzeit des Programms st&auml;rker erh&ouml;ht
+als im Modus &#187;samples&#171;. In der Praxis kann eine gemischte
+Vorgehensweise sinnvoll sein, bei der zun&auml;chst per &#187;samples&#171;
+die gr&ouml;&szlig;ten Performancefresser eliminiert werden und dann
+per &#187;times&#171; das Feintuning vorgenommen wird. Die Option
+&#187;old&#171; erstellt die Ausgabedatei in einem Format, wie sie
+von den Profilern der Pr&auml;-1.2-Versionen verwendet wurde. Wir
+wollen hier nicht weiter darauf eingehen.
+
+<p>
+Bei der Verwendung des CPU-Profilers sind weiterhin die Optionen <font color="#000077"><tt>file</tt></font>
+und <font color="#000077"><tt>depth</tt></font> von Bedeutung. Mit
+<font color="#000077"><tt>file</tt></font> kann der Name der Ausgabedatei
+angegeben werden, er ist standardm&auml;&szlig;ig <font color="#660099">java.hprof.txt</font>.
+Mit <font color="#000077"><tt>depth</tt></font> wird festgelegt, mit
+welcher maximalen Tiefe die Stacktraces aufgezeichnet werden (standardm&auml;&szlig;ig
+4). Ist die Aufrufkette einer Methode l&auml;nger als der angegebene
+Wert, wird der Stacktrace abgeschnitten, und bei der Analyse ist nicht
+mehr bis ins letzte Detail erkennbar, von welcher Stelle aus der Aufruf
+erfolgte. Wird <font color="#000077"><tt>depth</tt></font> auf 1 gesetzt,
+sind nur noch die Aufrufstellen sichtbar, die Aufrufer selbst bleiben
+unsichtbar.
+
+<p>
+Wir wollen einen ersten Lauf mit dem CPU-Profiler im Modus &#187;samples&#171;
+und mit einer maximalen Stacktiefe von 10 machen und rufen das Programm
+daher wie folgt auf:
+<font color="#333300">
+<pre>
+java -Xint -Xrunhprof:cpu=samples,depth=10 ProfTest1A
+</pre>
+</font>
+<p>
+<table border=0 cellspacing=0 cellpadding=0 width=100%>
+<tr>
+<td width=1 align=left valign=top bgcolor="#000077"><img src="trp1_1.gif"></td>
+<td><img src="trp1_1.gif" width=2></td>
+<td valign=top width=1000>
+
+<p>
+Die Option <a name="ixa103675"><a href="index_0.html#ixb102751"><font color=#000080><tt>-Xint</tt></font></a></a>
+geben wir an, um das Programm im Interpreter-Modus laufen zu lassen
+und m&ouml;gliche Verf&auml;lschungen durch den Hotspot-Compiler zu
+vermeiden.</td>
+<td><img src="trp1_1.gif" width=2></td>
+<td valign=top>
+<table border=0 cellspacing=0 cellpadding=1 width=100% bgcolor="#000077">
+<tr>
+<td><font color="#FFFFFF">&nbsp;Hinweis&nbsp;</font></td>
+</tr>
+</table>
+</td>
+<td width=1 align=left valign=top bgcolor="#000077"><img src="trp1_1.gif"></td>
+</tr>
+</table>
+
+
+<!-- Section -->
+<a name="sectlevel4id050003002002"></a>
+<h4>Das CPU-Profile </h4>
+
+<p>
+Das Programm erzeugt nun die Ausgabedatei <font color="#660099">java.hprof.txt</font>
+mit den Profiling-Informationen. Sie besteht aus drei Teilen:
+<ul>
+<li>Im oberen Teil werden allgemeine Informationen zur Struktur der
+Datei und den darin verwendeten Eintr&auml;gen gegeben
+<li>Im mittleren Teil befinden sich die Stacktraces
+<li>Im unteren Teil werden die Sampling-Ergebnisse ausgegeben
+</ul>
+
+<p>
+Die Analyse beginnt im unteren Teil. Er sieht bei unserer Beispielsitzung
+so aus (die Samples ab Position 11 wurden aus Gr&uuml;nden der &Uuml;bersichtlichkeit
+entfernt):
+<font color="#333300">
+<pre>
+CPU SAMPLES BEGIN (total = 246) Sun Jun 18 17:56:28 2000
+rank self accum count trace method
+ 1 53.66% 53.66% 132 9 java.lang.StringBuilder.expandCapacity
+ 2 17.48% 71.14% 43 13 java.lang.System.arraycopy
+ 3 17.07% 88.21% 42 11 java.lang.System.arraycopy
+ 4 1.63% 89.84% 4 10 java.lang.StringBuilder.toString
+ 5 1.22% 91.06% 3 17 java.lang.StringBuilder.append
+ 6 0.81% 91.87% 2 19 java.lang.StringBuilder.append
+ 7 0.81% 92.68% 2 24 sun.io.CharToByteSingleByte.convert
+ 8 0.81% 93.50% 2 12 java.lang.StringBuilder.&lt;init&gt;
+ 9 0.41% 93.90% 1 20 java.lang.StringBuilder.append
+ 10 0.41% 94.31% 1 14 java.lang.String.getChars
+ ...
+CPU SAMPLES END
+</pre>
+</font>
+
+<p>
+Die Ausgabe ist nach Aufrufh&auml;ufigkeit geordnet. Von den insgesamt
+246 Samples, die w&auml;hrend des Programmlaufs gezogen wurden, waren
+132 in der Methode <a name="ixa103676"><a href="index_e.html#ixb102752"><font color=#000080><tt>expandCapacity</tt></font></a></a>
+der Klasse <a href="index_s.html#ixb100545"><font color=#000080><tt>StringBuilder</tt></font></a>
+und 43 und noch einmal 42 in der Methode <a href="index_a.html#ixb100856"><font color=#000080><tt>arraycopy</tt></font></a>
+der Klasse <a href="index_s.html#ixb100435"><font color=#000080><tt>System</tt></font></a>.
+Damit fielen insgesamt 88.21 Prozent aller Samples in diese Methoden.
+
+<p>
+Da beide Methoden nicht selbstgeschrieben sind und sich damit unseren
+Optimierungsversuchen entziehen, kann eine Performance-Verbesserung
+lediglich dadurch erreicht werden, dass die Anzahl ihrer Aufrufe vermindert
+wird. Um die Aufrufer herauszufinden, m&uuml;ssen wir uns die in der
+f&uuml;nften Spalten angegebenen Stacktraces ansehen. Der Stacktrace
+zu <a href="index_e.html#ixb102752"><font color=#000080><tt>expandCapacity</tt></font></a>
+hat die Nummer 9 und sieht so aus:
+<font color="#333300">
+<pre>
+TRACE 9:
+ java.lang.StringBuilder.expandCapacity(StringBuilder.java:202)
+ java.lang.StringBuilder.append(StringBuilder.java:401)
+ ProfTest1A.dots(ProfTest1A.java:11)
+ ProfTest1A.main(ProfTest1A.java:18)
+</pre>
+</font>
+
+<p>
+Er besagt, dass der Sample in Zeile 202 der Methode <a href="index_e.html#ixb102752"><font color=#000080><tt>expandCapacity</tt></font></a>
+der Klasse <a href="index_s.html#ixb100545"><font color=#000080><tt>StringBuilder</tt></font></a>
+erzeugt wurde. Diese wurde von <a href="index_a.html#ixb100546"><font color=#000080><tt>append</tt></font></a>
+aufgerufen, das von unserer eigenen Methode <font color="#000077"><tt>dots</tt></font>
+in Zeile 11 aufgerufen wurde. In Zeile 11 steht zwar kein Aufruf von
+<a href="index_a.html#ixb100546"><font color=#000080><tt>append</tt></font></a>,
+dort befindet sich aber der +=-Operator zur Verkettung der Strings.
+Dieser wird vom Compiler in entsprechende Methoden- und Konstruktorenaufrufe
+der Klassen <a href="index_s.html#ixb100117"><font color=#000080><tt>String</tt></font></a>
+und <a href="index_s.html#ixb100545"><font color=#000080><tt>StringBuilder</tt></font></a>
+&uuml;bersetzt.
+
+<p>
+Als erste Erkenntnis stellen wir also fest, dass offensichtlich der
++=-Operator zur <a href="index_s.html#ixb100117"><font color=#000080><tt>String</tt></font></a>-Verkettung
+interne <a href="index_s.html#ixb100545"><font color=#000080><tt>StringBuilder</tt></font></a>-Objekte
+erzeugt, die einen erheblichen Teil der CPU-Zeit ben&ouml;tigen, um
+w&auml;hrend des Anf&uuml;gens von Zeichen vergr&ouml;&szlig;ert zu
+werden.
+
+<p>
+Die Stacktraces 11 und 13 der n&auml;chsten beiden Kandidaten verst&auml;rken
+den Eindruck, dass der +=-Operator in unserem Programm CPU-intensiven
+Code erzeugt:
+<font color="#333300">
+<pre>
+TRACE 11:
+ java.lang.System.arraycopy(System.java:Native method)
+ java.lang.String.getChars(String.java:553)
+ java.lang.StringBuilder.append(StringBuilder.java:402)
+ ProfTest1A.dots(ProfTest1A.java:11)
+ ProfTest1A.main(ProfTest1A.java:18)
+TRACE 13:
+ java.lang.System.arraycopy(System.java:Native method)
+ java.lang.StringBuilder.expandCapacity(StringBuilder.java:203)
+ java.lang.StringBuilder.append(StringBuilder.java:401)
+ ProfTest1A.dots(ProfTest1A.java:11)
+ ProfTest1A.main(ProfTest1A.java:18)
+</pre>
+</font>
+
+<p>
+Beide Arten von Samples gehen letztlich auf Zeile 11 unseres Programms
+zur&uuml;ck und zeigen Rechenzeitverbr&auml;uche, die durch die vom
++=-Operator ausgel&ouml;ste Verarbeitung tempor&auml;rer Strings und
+StringBuilder verursacht werden. Obwohl die Samples in beiden F&auml;llen
+in <a href="index_a.html#ixb100856"><font color=#000080><tt>arraycopy</tt></font></a>
+gezogen wurden, gibt es zwei unterschiedliche Stacktraces, weil die
+Aufruferkette in beiden F&auml;llen unterschiedlich ist. Einerseits
+wird <a href="index_a.html#ixb100856"><font color=#000080><tt>arraycopy</tt></font></a>
+aus <a href="index_g.html#ixb102742"><font color=#000080><tt>getChars</tt></font></a>
+aufgerufen (da Strings immutable sind, muss <a href="index_g.html#ixb102742"><font color=#000080><tt>getChars</tt></font></a>
+bei jedem Aufruf eine Kopie des Zeichenarrays erstellen), andererseits
+wird <a href="index_a.html#ixb100856"><font color=#000080><tt>arraycopy</tt></font></a>
+in <a href="index_e.html#ixb102752"><font color=#000080><tt>expandCapacity</tt></font></a>
+ben&ouml;tigt, um das bei einer Verl&auml;ngerung des StringBuilders
+erforderliche Umkopieren der Zeichen zu erledigen.
+
+<p>
+Unsere erste Vermutung hat sich also best&auml;tigt: Der harmlos aussehende
+Aufruf des +=-Operators in Zeile 11 unseres Programms erzeugt tempor&auml;re
+<a href="index_s.html#ixb100117"><font color=#000080><tt>String</tt></font></a>-
+und <a href="index_s.html#ixb100545"><font color=#000080><tt>StringBuilder</tt></font></a>-Objekte,
+in der ein Gro&szlig;teil der Rechenzeit durch das Anh&auml;ngen und
+Kopieren von Zeichen und das Erh&ouml;hen der Kapazit&auml;t verbraucht
+wird.
+
+<!-- Section -->
+
+<a name="sectlevel4id050003002003"></a>
+<h4>Das Heap-Profile </h4>
+
+<p>
+Einen noch deutlicheren Eindruck vermittelt ein Heap-Profile. Wir
+erstellen es, indem wir das Programm mit der Option <font color="#000077"><tt>heap=sites</tt></font>
+erneut unter Profiler-Kontrolle laufen lassen:
+<font color="#333300">
+<pre>
+java -Xint -Xrunhprof:heap=sites,depth=10 ProfTest1A
+</pre>
+</font>
+
+<p>
+Die Ausgabe besteht wie beim CPU-Profiling aus drei Teilen. Die ersten
+beiden entsprechen dem CPU-Profiler, der dritte enth&auml;lt Informationen
+zur dynamischen Heap-Belegung:
+<font color="#333300">
+<pre>
+SITES BEGIN (ordered by live bytes) Sun Jun 18 18:37:28 2000
+ percent live alloc'ed stack class
+ rank self accum bytes objs bytes objs trace name
+ 1 48.27% 48.27% 189974 25 75074238 19950 471 [C
+ 2 38.00% 86.27% 149524 157 149524 157 1 [I
+ 3 4.91% 91.17% 19304 741 19364 747 1 [C
+ 4 2.44% 93.61% 9588 153 9588 153 1 [B
+ 5 2.29% 95.90% 9010 1550 9022 1552 1 &lt;Unknown&gt;
+ 6 1.13% 97.03% 4460 199 4460 199 1 [S
+ 7 1.06% 98.09% 4164 253 4220 260 1 [L&lt;Unknown&gt;;
+ 8 0.06% 98.15% 238 3 238 3 403 [B
+ 9 0.04% 98.20% 172 1 172 1 396 [B
+ 10 0.04% 98.24% 170 10 170 10 390 [C
+ ...
+SITES END
+</pre>
+</font>
+
+<p>
+Auch hier geben die erste Spalte die Rangordnung und die n&auml;chsten
+beiden die einzelnen und kumulierten Prozentanteile am Gesamtverbrauch
+an. die Spalten 4 und 5 geben einen &Uuml;berblick &uuml;ber die aktiven
+Objekte, die n&auml;chsten beiden &uuml;ber die insgesamt allozierten
+Objekte (jeweils mit der Gesamtzahl allozierter Bytes und der Anzahl
+der Objekte). Die letzte Spalte stellt den Datentyp des Objekts dar.
+<a name="ixa103677"><a href="index_0.html#ixb102753"><font color=#000080><tt>[C</tt></font></a></a>
+steht beispielsweise f&uuml;r ein Zeichen-Array, <a name="ixa103678"><a href="index_0.html#ixb102754"><font color=#000080><tt>[I</tt></font></a></a>
+f&uuml;r ein Integer-Array.
+
+<p>
+Am auff&auml;lligsten ist die oberste Zeile und die darin ersichtliche
+Diskrepanz zwischen aktiven und allozierten Objekten. Dort steht,
+dass unser Programm 19950 Zeichen-Arrays mit insgesamt 75 MByte Speicher
+alloziert hat, davon aber nur noch 25 Objekte mit kaum 200 kByte Speicher
+aktiv sind. Hier wurden also in erheblichen Umfang kurzlebige Objekte
+erzeugt und anschlie&szlig;end wieder fallengelassen. Stacktrace 471
+sieht so aus:
+<font color="#333300">
+<pre>
+TRACE 471:
+ java.lang.StringBuilder.expandCapacity(StringBuilder.java:202)
+ java.lang.StringBuilder.append(StringBuilder.java:401)
+ ProfTest1A.dots(ProfTest1A.java:11)
+ ProfTest1A.main(ProfTest1A.java:18)
+</pre>
+</font>
+
+<p>
+Wieder liegt der Verursacher in Zeile 11 unseres Programms, und wir
+sehen, dass der +=-Operator nicht nur viel Rechenzeit verbraucht,
+sondern zudem eine gro&szlig;e Anzahl tempor&auml;rer Objekte erzeugt
+und damit das Laufzeitsystem und den Garbage Collector belastet.
+
+<!-- Section -->
+
+<a name="sectlevel4id050003002004"></a>
+<h4>Die optimierte Version des Programms </h4>
+
+<p>
+Da wir auf die Interna der Klassen <a href="index_s.html#ixb100117"><font color=#000080><tt>String</tt></font></a>
+und <a href="index_s.html#ixb100545"><font color=#000080><tt>StringBuilder</tt></font></a>
+keinen Einfluss haben, kann die Optimierung nur darin bestehen, die
+Verwendung des +=-Operators einzuschr&auml;nken oder eine besser geeignete
+Alternative zu w&auml;hlen. Diese ist nat&uuml;rlich schon aus <a href="k100314.html#tuningstring">Abschnitt 50.2.1</a>
+bekannt und besteht darin, direkt mit <a href="index_s.html#ixb100545"><font color=#000080><tt>StringBuilder</tt></font></a>-Objekten
+zu arbeiten. Die verbesserte Version unseres Programms sieht dann
+so aus:
+<a name="proftest1b"></a>
+
+<p>
+<table border=0 cellspacing=0 cellpadding=0 width=100% bgcolor="#DDDDDD">
+<tr>
+<td valign=top>
+<font color="#000055">
+<pre>
+<font color="#555555">001 </font><font color="#00AA00">/* ProfTest1B.java */</font>
+<font color="#555555">002 </font>
+<font color="#555555">003 </font><font color="#0000AA">import</font> java.util.*;
+<font color="#555555">004 </font>
+<font color="#555555">005 </font><font color="#0000AA">public</font> <font color="#0000AA">class</font> ProfTest1B
+<font color="#555555">006 </font>{
+<font color="#555555">007 </font> <font color="#0000AA">public</font> <font color="#0000AA">static</font> String dots(<font color="#006699">int</font> len)
+<font color="#555555">008 </font> {
+<font color="#555555">009 </font> StringBuilder sb = <font color="#0000AA">new</font> StringBuilder(len + 10);
+<font color="#555555">010 </font> <font color="#0000AA">for</font> (<font color="#006699">int</font> i = 0; i &lt; len; ++i) {
+<font color="#555555">011 </font> sb.append(<font color="#0000FF">'.'</font>);
+<font color="#555555">012 </font> }
+<font color="#555555">013 </font> <font color="#0000AA">return</font> sb.toString();
+<font color="#555555">014 </font> }
+<font color="#555555">015 </font>
+<font color="#555555">016 </font> <font color="#0000AA">public</font> <font color="#0000AA">static</font> <font color="#006699">void</font> main(String[] args)
+<font color="#555555">017 </font> {
+<font color="#555555">018 </font> String s = dots(10000);
+<font color="#555555">019 </font> System.out.println(s); <a name="proftest1b.a"></a>
+<font color="#555555">020 </font> }
+<font color="#555555">021 </font>}</pre>
+</font>
+</td>
+<td valign=top align=right>
+<a href="../examples/ProfTest1B.java"><font color="#000055" size=-1>ProfTest1B.java</font></a></td>
+</tr>
+</table>
+<i>
+Listing 50.10: Das verbesserte Programm nach der Profiler-Sitzung</i></p>
+
+<p>
+Wird nun ein CPU-Profiling durchgef&uuml;hrt, ergibt sich ein g&auml;nzlich
+anderes Bild:
+<font color="#333300">
+<pre>
+CPU SAMPLES BEGIN (total = 15) Sun Jun 18 19:03:56 2000
+rank self accum count trace method
+ 1 26.67% 26.67% 4 9 sun.io.CharToByteSingleByte.convert
+ 2 6.67% 33.33% 1 2 java.io.InputStreamReader.&lt;init&gt;
+ 3 6.67% 40.00% 1 12 sun.io.CharToByteSingleByte.getNative
+ 4 6.67% 46.67% 1 11 sun.io.CharToByteSingleByte.convert
+ 5 6.67% 53.33% 1 13 java.io.FileOutputStream.writeBytes
+ 6 6.67% 60.00% 1 4 sun.security.provider.PolicyFile.getPermissions
+ 7 6.67% 66.67% 1 5 sun.net.www.protocol.file.FileURLConnection.getPermission
+ 8 6.67% 73.33% 1 10 java.io.FileOutputStream.writeBytes
+ 9 6.67% 80.00% 1 1 sun.misc.URLClassPath$FileLoader.getResource
+ 10 6.67% 86.67% 1 6 java.net.URLClassLoader.getPermissions
+ 11 6.67% 93.33% 1 3 java.security.Security.loadProviders
+ 12 6.67% 100.00% 1 8 java.lang.StringBuilder.append
+CPU SAMPLES END
+</pre>
+</font>
+
+<p>
+Statt 246 gab es nur noch 15 Samples (die Laufzeit des Programms hat
+sich also auf ein Sechzehntel reduziert), und nur noch ein einziger
+von ihnen wurde durch den Aufruf der Methode <font color="#000077"><tt>dots</tt></font>
+verursacht. Alle anderen sind auf den Aufruf von <a href="index_p.html#ixb100555"><font color=#000080><tt>println</tt></font></a>
+in <a href="k100315.html#proftest1b.a">Zeile 019</a> zur&uuml;ckzuf&uuml;hren.
+Der Heap-Profiler liefert ein &auml;hnliches Bild: der gesamte Speicherverbrauch
+des Programms liegt nun in der Gr&ouml;&szlig;enordnung von 150 kByte,
+und es gibt keine nennenswerten tempor&auml;ren Objektallokationen
+mehr.
+<p>
+<table border=0 cellspacing=0 cellpadding=0 width=100%>
+<tr>
+<td width=1 align=left valign=top bgcolor="#FF9900"><img src="trp1_1.gif"></td>
+<td><img src="trp1_1.gif" width=1></td>
+<td width=1 align=left valign=top bgcolor="#FF9900"><img src="trp1_1.gif"></td>
+<td><img src="trp1_1.gif" width=2></td>
+<td valign=top width=1000>
+
+<p>
+In fr&uuml;heren JDKs wurde der Profiler nicht mit der Option <a name="ixa103679"><a href="index_0.html#ixb102750"><font color=#000080><tt>-Xrunhprof</tt></font></a></a>,
+sondern mit <a name="ixa103680"><a href="index_0.html#ixb102755"><font color=#000080><tt>-Xprof</tt></font></a></a>
+bzw. mit <a name="ixa103681"><a href="index_0.html#ixb102756"><font color=#000080><tt>-prof</tt></font></a></a>
+aufgerufen. Zudem durfte nicht der normale Interpreter verwendet werden,
+sondern mit <a name="ixa103682"><a href="index_j.html#ixb102757"><font color=#000080><tt>java_g</tt></font></a></a>
+mu&szlig;te dessen Debug-Version aufgerufen werden. Auch das Deaktivieren
+des Just-In-Time-Compilers hat sich im Laufe der Versionen ge&auml;ndert.
+W&auml;hrend es seit dem JDK 1.3 mit dem Schalter <a name="ixa103683"><a href="index_0.html#ixb102751"><font color=#000080><tt>-Xint</tt></font></a></a>
+erledigt wird, mu&szlig;te zuvor die Umgebungsvariable <a name="ixa103684"><a href="index_j.html#ixb102758"><font color=#000080><tt>JAVA_COMPILER</tt></font></a></a>
+auf den Wert <font color="#000077"><tt>NONE</tt></font> gesetzt werden.
+Soll der Profiler bei einem Applet verwendet werden, kann die Aufrufoption
+mit dem Schalter <a name="ixa103685"><a href="index_0.html#ixb102759"><font color=#000080><tt>-J</tt></font></a></a>
+an den Appletviewer &uuml;bergeben werden.</td>
+<td><img src="trp1_1.gif" width=2></td>
+<td valign=top>
+<table border=0 cellspacing=0 cellpadding=1 width=100% bgcolor="#FF9900">
+<tr>
+<td><font color="#FFFFFF">&nbsp;JDK1.1-6.0&nbsp;</font></td>
+</tr>
+</table>
+</td>
+<td width=1 align=left valign=top bgcolor="#FF9900"><img src="trp1_1.gif"></td>
+</tr>
+</table>
+
+
+<!-- Section -->
+<a name="sectlevel3id050003003"></a>
+<h3>50.3.3 Ausblick </h3>
+
+<p>
+Egal, ob mit dem eingebauten Profiler das Laufzeitverhalten oder der
+Speicherverbrauch der Anwendung untersucht werden soll, die prinzipielle
+Vorgehensweise ist stets gleich:
+<ul>
+<li>Zun&auml;chst wird das Programm mit der Option <font color="#000077"><tt>-Xrunhprof</tt></font>
+gestartet und eine Datei mit Profiling-Informationen erstellt.
+<li>Die gr&ouml;&szlig;ten Rechenzeit- und Speicherverbraucher werden
+ermittelt, und &uuml;ber ihre Stacktraces wird bestimmt, woher sie
+aufgerufen werden und in welcher Weise sie zum Programmergebnis beitragen.
+<li>Stehen gen&uuml;gend Erkenntnisse zur Verf&uuml;gung, kann das
+Programm verbessert werden und ein erneuter Profilerlauf durchgef&uuml;hrt
+werden.
+<li>Sind die Ergebnisse zufriedenstellend, kann der Profiler deaktiviert
+werden, andernfalls beginnt das Spiel von vorne.
+</ul>
+
+<p>
+Ist der Anteil von lokalem Code am Rechenzeitverbrauch hoch, kann
+versucht werden, diesen zu verringern. Typische Ansatzpunkte daf&uuml;r
+sind das Vermindern der Anzahl von Schleifendurchl&auml;ufen (durch
+bessere Algorithmen), die Verwendung von Ganz- statt Flie&szlig;kommazahlen,
+das Herausziehen von schleifeninvariantem Code, das Vermeiden der
+Doppelauswertung von gemeinsamen Teilausdr&uuml;cken, das Wiederverwenden
+bekannter Teilergebnisse, die Verwendung alternativer Datenstrukturen,
+das Eliminieren von unbenutztem Code oder das Reduzieren der St&auml;rke
+von Ausdr&uuml;cken, indem sie durch algebraisch gleichwertige, aber
+schnellere Ausdr&uuml;cke ersetzt werden. Wird ein gro&szlig;er Anteil
+der Rechenzeit dagegen in Aufrufen von Untermethoden verbraucht, kann
+versucht werden, deren Aufrufh&auml;ufigkeit zu vermindern, sie durch
+performantere Aufrufe zu ersetzen, oder - im Falle eigener Methoden
+- ihre Ablaufgeschwindigkeit zu erh&ouml;hen.
+
+<p>
+Der zielgerichtete Einsatz dieser Techniken erfordert gute Werkzeuge,
+namentlich einen guten Profiler. Bei kleineren Problemen mag es ausreichend
+sein, die Ablaufgeschwindigkeit mit Ausgabeanweisungen und <a name="ixa103686"><a href="index_s.html#ixb102760"><font color=#000080><tt>System.currentTimeMillis</tt></font></a></a>
+zu ermitteln, und auch der JDK-Profiler kann mit Erfolg eingesetzt
+werden. Daneben gibt es einige kommerzielle und experimentelle Produkte
+mit wesentlich erweiterten F&auml;higkeiten. Beispiele f&uuml;r solche
+Profiler sind <a name="ixa103687"><i>JProbe</i></a> (<a href="http://www.quest.com/jprobe/">http://www.quest.com/jprobe/</a>),
+der auch f&uuml;r Teile der Software zu diesem Buch verwendet wurde
+oder <a name="ixa103688"><i>JInsight</i></a> (<a href="http://www.alphaWorks.ibm.com">http://www.alphaWorks.ibm.com</a>).
+Zu ihren F&auml;higkeiten z&auml;hlen beispielsweise:
+<ul>
+<li>Die grafische Darstellung der Aufrufhierarchie mit Laufzeitinformationen
+zu Methoden und Aufrufen.
+<li>Das Ermitteln von Profiling-Informationen bis auf die Ebene einzelner
+Quelltextzeilen hinab.
+<li>Das Erstellen dynamischer Profile, um die Ver&auml;nderung wichtiger
+Parameter bereits w&auml;hrend des laufenden Programms beobachten
+zu k&ouml;nnen.
+<li>Die R&uuml;ckverfolgung von alloziertem Speicher sowohl zu den
+Programmstellen, die den Speicher belegt haben, als auch zu den Variablen,
+in denen die zugeh&ouml;rigen Objekte gehalten werden.
+<li>Das Vergleichen von Profiling-L&auml;ufen, um die Auswirkungen
+von Optimierungsversuchen studieren zu k&ouml;nnen.
+<li>Die Ausgabe von Reports und HTML-Dateien zu Vergleichs- und Dokumentationszwecken.
+</ul>
+<hr>
+<table border=0 cellpadding=0 cellspacing=1 width="100%">
+<tr bgcolor="#EEFFCC">
+<td width="7%" align=center bgcolor="#DDCC99"><a href="cover.html">&nbsp;Titel&nbsp;</a>
+<td width="7%" align=center bgcolor="#DDCC99"><a href="k100003.html">&nbsp;Inhalt&nbsp;</a>
+<td width="7%" align=center bgcolor="#DDCC99"><a href="search.html">&nbsp;Suchen&nbsp;</a>
+<td width="7%" align=center bgcolor="#DDCC99"><a href="index.html">&nbsp;Index&nbsp;</a>
+<td width="7%" align=center bgcolor="#DDCC99"><a href="../jdkdocs/index.html" onClick="this.href=getDocIndex()">&nbsp;DOC&nbsp;</a>
+<td align="right">Handbuch der Java-Programmierung, 5. Auflage, Addison
+Wesley, Version 5.0.1
+<tr bgcolor="#EEFFCC">
+<td width="7%" align=center bgcolor="#DDCC99"><a href="k100312.html">&nbsp;&lt;&lt;&nbsp;</a>
+<td width="7%" align=center bgcolor="#DDCC99"><a href="k100314.html">&nbsp;&nbsp;&lt;&nbsp;&nbsp;</a>
+<td width="7%" align=center bgcolor="#DDCC99"><a href="k100316.html">&nbsp;&nbsp;&gt;&nbsp;&nbsp;</a>
+<td width="7%" align=center bgcolor="#DDCC99"><a href="k100317.html">&nbsp;&gt;&gt;&nbsp;</a>
+<td width="7%" align=center bgcolor="#DDCC99"><a href="../jdkdocs/api/index.html" onClick="this.href=getApiIndex()">&nbsp;API&nbsp;</a>
+<td align="right">&copy; 1998, 2007 Guido Kr&uuml;ger &amp; Thomas
+Stark, <a href="http://www.javabuch.de">http://www.javabuch.de</a>
+</table>
+<a name="endofbody"></a>
+</body>
+</html>