Java Performance Tools – Teil 1 (Grundlagen)
Java Performance Tools – Teil 1 (Grundlagen)
Java Performance Tools – Teil 1 (Grundlagen)
Sie wollen auch ein ePaper? Erhöhen Sie die Reichweite Ihrer Titel.
YUMPU macht aus Druck-PDFs automatisch weboptimierte ePaper, die Google liebt.
ten technischen Probleme komplexer <strong>Java</strong>-Anwendungen<br />
sind dabei:<br />
•Schlechte <strong>Performance</strong><br />
•Memory Leaks und OutOfMemoryError<br />
•Garbage Collection Overhead<br />
•Deadlocks und Loops<br />
•Synchronisations- und Thread-Safety-<br />
Probleme.<br />
Die Auswirkungen dieser Probleme sind<br />
vielfältig und reichen von schlechten Antwortzeiten,<br />
einer geringen Anzahl paralleler<br />
Benutzer, bis hin zu einem Ausfall des<br />
gesamten Systems und korrupten Daten.<br />
Dies führt bei geschäftskritischen, produktiven<br />
Systemen unweigerlich zu einer<br />
Eskalation im Management, an deren Ende<br />
leider immer die Entwickler stehen. Die<br />
Aufgabe ist klar und einfach formuliert:<br />
Die Probleme schnell identifizieren und<br />
noch schneller beseitigen. Aber wie?<br />
<strong>Tools</strong> für die Analyse<br />
Es gibt unterschiedliche <strong>Tools</strong>, um die<br />
beschriebenen Probleme zu analysieren.<br />
Eine der entscheidenden Fragen ist, wie<br />
viele Informationen man für die Lösungsfindung<br />
benötigt und unter welchen Bedingungen<br />
man eine Analyse durchführen<br />
kann. Eine Faustregel ist: Je mehr Daten<br />
von einem Tool gesammelt werden, desto<br />
höher ist der Einfluss des <strong>Tools</strong> auf die<br />
Anwendung selbst. Es gibt zum Beispiel<br />
kein Tool, das einen kompletten Memory<br />
Dump inklusive Referenzen erzeugen<br />
kann, ohne das System de facto zum Stillstand<br />
zu bringen. Aus diesem Grund unterscheidet<br />
man drei Arten von <strong>Tools</strong>:<br />
•Monitoring-<strong>Tools</strong> eignen sich für den<br />
Einsatz in produktiven Umgebungen.<br />
Diese <strong>Tools</strong> haben einen akzeptablen<br />
Overhead und liefern Informationen<br />
über Probleme in laufenden Anwendungen<br />
bis auf Komponentenlevel. Mithilfe<br />
von Trendanalysen und längerfristigen<br />
Betrachtungen, können Probleme<br />
proaktiv vermieden werden.<br />
•Diagnose-<strong>Tools</strong> sind für den Einsatz in<br />
Integrations- und Testumgebungen geeignet.<br />
Diese <strong>Tools</strong> können auch unter<br />
erzeugter Last detaillierte Analysedaten<br />
bis auf Methodenlevel liefern und ha-<br />
www.javamagazin.de<br />
ben noch einen akzeptablen Overhead.<br />
Gerade für Probleme, die nur unter erhöhter<br />
Belastung auftreten und nicht in<br />
der Entwicklungsumgebung, sind diese<br />
<strong>Tools</strong> unverzichtbar.<br />
•Profiler und Memory Debugger sind<br />
für den Einsatz in der Entwicklungsumgebung<br />
ausgelegt und können <strong>Performance</strong>-Informationen<br />
bis auf Zeilenebene<br />
liefern. Mithilfe von Memory<br />
Debuggern können zudem Memory<br />
Leaks analysiert werden. Der Overhead,<br />
gerade bei der Memory-Analyse,<br />
ist sehr hoch und man kann diese <strong>Tools</strong><br />
nicht in produktiven Umgebungen einsetzen.<br />
Im Folgenden werden die Technologien<br />
beschrieben, auf denen diese <strong>Tools</strong> basieren.<br />
Des Weiteren werden die integrierten<br />
<strong>Tools</strong> in der JVM und dem JDK vorgestellt<br />
und anhand von Problemszenarien<br />
beschrieben.<br />
JVM Tooling Interface<br />
Die <strong>Java</strong> Virtual Machine verfügt seit der<br />
Version 1.2 über eine Schnittstelle für<br />
Profiling <strong>Tools</strong>, das <strong>Java</strong> Virtual Machine<br />
Profiling Interface (JVMPI). Die Schnittstelle<br />
definiert die Funktionen für einen in<br />
C oder C++ geschriebenen Agenten, der<br />
sich für die wichtigsten JVM Events registrieren<br />
kann. Zu den Events, für die sich<br />
ein Agent registrieren kann, zählen:<br />
•JVM Life Cycle Events: Für die Initialisierungsphase<br />
der JVM<br />
•Class Life Cycle Events: Load und Unload<br />
einer Klasse. Der Profiling Agent<br />
hat zusätzlich die Möglichkeit, den Inhalt<br />
der Klasse zu lesen und zu verändern<br />
•Thread Life Cycle Events: Für das Erzeugen<br />
und Zerstören von Threads<br />
•Objekt Life Cycle Events: Bei Allokation,<br />
Löschen und Verschieben von<br />
Objekten auf dem Heap durch den Gar-<br />
bage Collector<br />
•Method Call Events: Entry und Exit jeder<br />
aufgerufenen Methode<br />
•Monitor Event <strong>–</strong> Anfrage, Enter, Exit<br />
und Wait auf einen <strong>Java</strong>-Monitor (synchronized<br />
und Object.wait())<br />
•GC Events: Beim Start und Ende der<br />
GC-Phase.<br />
Sonderdruck<br />
Neben diesen Events besteht die Möglichkeit,<br />
über den Agenten einen vollständigen<br />
Heapdump zu erzeugen, das<br />
heißt, alle Objekte auf dem Heap inklusive<br />
der Referenzen in eine Datei zu schreiben.<br />
JVMPI ist allerdings kein Standard<br />
und muss somit nicht zwingend von<br />
allen JVM-Herstellern unterstützt werden<br />
bzw. kann in der Implementierung<br />
abweichen. Mit JSR 163 (<strong>Java</strong> Platform<br />
Profiling Architecture) wurde ein Standard<br />
entwickelt, der in <strong>Java</strong> 5 als <strong>Java</strong><br />
Virtual Maschine Tool Interface (JVM-<br />
TI) eingegangen ist. JVMTI basiert auf<br />
dem Agenten-Konzept von JVMPI, sodass<br />
auch hier ein C- oder C++-Agent<br />
entwickelt werden muss, der sich dann<br />
für bestimmte Events registrieren und<br />
Funktionen der JVM steuern kann. Eine<br />
weitere, sehr interessante Erweiterung<br />
von JVMTI ist, dass der Inhalt einer Klasse<br />
nicht mehr nur zur Ladezeit verändert<br />
werden kann, sondern auch dynamisch<br />
zu einem späteren Zeitpunkt des Lebenszyklus<br />
einer Klasse.<br />
Die Events von JVMPI und JVMTI<br />
liefern die benötigten Daten, um <strong>Performance</strong>,<br />
Speicher, Threading- und Gar-<br />
bage-Collection-Probleme im Detail zu<br />
analysieren. Das ist auch der Grund, wa-<br />
rum <strong>Java</strong> Profiling und Memory Debugger<br />
fast ausschließlich auf Basis dieses<br />
Agentenkonzepts funktionieren. Der hohe<br />
Detailgrad hat aber seinen Preis und resultiert<br />
in einem <strong>Performance</strong> Overhead,<br />
der zu groß ist, um diese <strong>Tools</strong> in Produktion<br />
oder Lasttestumgebungen in vollem<br />
Umfang einzusetzen. Monitoring und Diagnose-<strong>Tools</strong>,<br />
die mit geringem Overhead<br />
arbeiten, nutzen daher in der Regel eine<br />
Form der Bytecode-Instrumentierung für<br />
die Erfassung von Laufzeitdaten.<br />
Bytecode-Instrumentierung<br />
Mit Bytecode-Instrumentierung werden<br />
die Techniken zur nachträglichen Veränderung<br />
des compilierten Bytecodes<br />
einer <strong>Java</strong>-Anwendung bezeichnet. <strong>Performance</strong><br />
<strong>Tools</strong> nutzen diese Technik,<br />
um den eigentlichen Messcode in den<br />
bestehenden Applikationscode einzufügen.<br />
Mithilfe von Libraries wie der<br />
Apache Byte Code Engineering Library<br />
(BCEL) [1] wird der bestehende Bytecode<br />
analysiert und dann ein neuer Bytecode<br />
Sonderdruck