ArtikelJuli 2008

Memory Analyse Teil 1 – Java Heapdumps erzeugen

Bei Troubleshooting Einsätzen ist der Java Heapdump eines der wichtigsten Hilfsmittel, um Memory Leaks oder hohen Speicherverbrauch zu analysieren. Der Vorteil von Heapdumps ist, dass man sie auch in produktiven Umgebungen erzeugen kann  – also da wo die Probleme am häufigsten auftreten. Alle aktuellen Java Virtual Maschines unterstützen die Erzeugung von Heapdumps, ohne zusätzliche Tools installieren zu müssen.

In dieser Blog Serie möchte ich zeigen, wie man Memory Probleme analysieren und beheben kann. Dazu werden Antipatterns und unterschiedliche Memory Probleme beschrieben und Lösungsszenarien aufgezeigt.

Der erste Teil zu diesem Thema beschäftigt sich mit der elementaren Aufgabe einen Heapdump zu erzeugen – die wichtigste Voraussetzung für eine erfolgreiche Analyse.  Die unterschiedlichen Hersteller von JVMs (Sun, IBM, BEA) haben unterschiedliche Werkzeuge und Dump Formate in die JVMs integriert – dieser Blog wird die Implementierung von Sun betrachten und am Ende Hinweise für andere Implementierungen geben.

Die Sun Java Virtual Maschine enthält mehere Tools und Optionen, um einen Heapdump zu erstellen:

- Automatisch bei einem java.lang.OutOfMemoryError

- Über das Kommandozeilen Tool jmap

- Über ein bereitgestelltes MBean (Java Management Extension – JMX) und das Tool jconsole

Natürlich gibt es auch die Möglichkeit über das Java Virtual Maschine Tool Interface (JVMTI) einen Dump zu erzeugen – allerdings muss man hierfür einen Agenten in C erstellen. Viele Profiler (JProfiler, dynaTrace Diagnostics) bieten aber die Möglichkeit eine Dump über JVMTI zu erzeugen und die Daten grafisch auszuwerten.

Um automatisch einen Heapdump zu erzeugen, wenn ein OutOfMemoryError geworfen wird, muss man einen JVM Kommandozeilen Parameter beim Start von java mitgeben:

-XX:+HeapDumpOnOutOfMemoryError

Der Parameter bewirkt, dass die JVM bei einem OutOfMemoryError einen Headump im HPROF Format in das aktuelle Verzeichnis schreibt. Der Name des Dumps entspricht der Konvention java_pid.hprof.  Um das Verzeichnis und den Namen der Datei selber zu bestimmen, kann man zusätzlich den Parameter -XX:HeapDumpPath=path_to_file definieren.

Die automatische Erzeugung von Dumps über Parameter ist allerdings nicht immer sinnvoll. In manchen Situation möchte man den Dump auch im laufenden Betrieb erzeugen. Für diesen Fall liefert Java ab Version 1.4.2_09, 1.5.x und 1.6.x das Tool jmap mit. Einen Heapdump im HPROF Format erzeugt man mit durch den Kommandozeilen Befehl jmap -dump:file=path_to_file java_process_id. Die Java Prozess Id legt fest von welcher aktiven, lokalen JVM der Headump angefordert werden soll. Die Prozess Id kann man mit dem JVM Tool jps ermitteln. (Hinweis: Das Tool jmap ist allerdings nicht jeder Plattform und JVM Version verfügbar) Alternativ kann man auch den JVM Parameter -XX:+HeapDumpOnCtrlBreak nutzen und dem Prozess ein SIGQUIT Signal (kill -3 bei Unix und Ctrl-Break bei Windows) senden.

Mit Java 6 hat Sun zusätzlich ein JMX MBean eingeführt, das Methoden zum Erzeugen eines Heapdumps enthält. Um einen Dump über JMX zu erzeugen startet man die integrierte JMX Konsole mit dem Befehl jconsole und verbindet sich mit der entsprechenden JVM. Lokal ist dafür keine weitere Konfiguration der JVM notwendig – möchte man auf eine JVM auf einem anderen Rechner zugreifen, muss JMX entsprechend konfiguriert sein.

Unter der Lasche MBean findet man einen Explorer mit den verfügbaren MBean innerhalb der JVM. Das MBean com.sun.management.HotSpotDiagnostic enthält die gesuchte Methode dumpHeap(String, boolean). Mit Hilfe des ersten String Parameters kann der Pfad und der Name des Heapdumps angegeben werden. Der Screenshot zeigt die entsprechende Ansicht. Drückt man auf den dumpHeap-Button wird ein Memory-Dump der JVM ausgeführt.

Der nächste Teil dieser Serie wird sich mit der Auswertung und dem Aufbau eines Heapdumps beschäftigen und erste Tips zur Analyse von Memory Problemen geben.

Informationen wie man Heapdumps mit der IBM JVM erzeugt finden sich in der IBM JVM Diagnosis Documentation.

Information zu BEA JRockit und dem JRockit Memory Leak Detector finde sich in der JRockit Dokumentation.

Mirko Novakovic

 

codecentric präsentiert Scrum für virtuelle Teams bei der JUG Köln

JUG Cologne LogoDie JUG Cologne hat mich zu einem ihrer regelmäßigen Treffen eingeladen. Am 11. August werde ich die Erfahrungen präsentieren, die ich als Spec-Lead für Java Specification Request 264 (Eine Order Management API) gemacht habe, als wir in der Expert Group Scrum eingeführt haben. Nach einer allgemeinen Einführung in Scrum werde ich sowohl auf die Gründe eingehen, die uns dazu motiviert haben, Scrum in einem global verteilten, virtuellem Team auszuprobieren, als auch die vom Team entwickelten Lösungen um mit Problemen wie unterschiedlichen Zeitzonen und variierende Verfügbarkeit der Teammitglieder umzugehen. Ausserdem analysiere ich kurz welche Effekte die neue Arbeitsweise auf die Gruppendynamik hatte. (weiterlesen…)

Andreas Ebbert-Karroum

 

Internet Explorer 8 wird neue AJAX-Funktionalität enthalten

Ein Blog-Eintrag bei MSDN berichtet von einer wesentlichen Neuerung im Internet Explorer 8: es wird eine Steuerung der Navigationshistorie per JavaScript geben.

Bisher war es für den Anwender AJAX-basierter Webanwendungen problematisch, vor- und rückwärts durch die Anwendung zu navigieren. Nach dem Laden der Seite wird unter Umständen der Zustand des HTML-Dokuments durch AJAX verändert, zum Beispiel durch dynamisches Nachladen von Texten oder Daten. Klickt der Anwender in seinem Browser auf “zurück”, so springt der Browser zurück zur vorher geladenen Seite in der Anwendung. Damit geht der komplette, per AJAX veränderte Zustand, verloren.

Die neue Implementierung im Internet Explorer 8, adaptiert aus HTML 5, soll dieses Problem beheben. Es wird dann möglich sein, AJAX-basierte Vorgänge mit in die Navigationshistorie aufzunehmen, so dass der Anwender wieder nach dem altbekannten Vor-/Zurück-Prinzip durch die Applikation navigieren kann. Damit wäre ein großes Usability-Problem mit AJAX-Anwendungen gelöst.

Das neue Feature wird hier als Video präsentiert.

Über die Adaption dieser Funktionalität in Firefox oder anderen Browsern gibt es derzeit noch keine konkreten Aussagen. Man wird abwarten müssen, wie sich die einzelnen Hersteller orientieren.

Robert Spielmann

 

Seiteneffekte beim Connection-Sharing

Heute hatten Christian und ich es mit einem sehr mysteriösen Connection Problem zu tun. Als Teil einer Prozesskette schlug ein Rest WebService Aufruf fehl. Jedoch tat er dies nur unter Last. Auf Grund dessen wollten wir das Laufzeitverhalten auch nicht durch Debugging Breakpoints zu sehr beeinflussen und beschränkten uns auf Debug-Logausgaben. Dabei war dem nicht ganz einfach beizukommen: Der WebService Client ist eine Erweiterung des Apache Commons HTTPclient. Der Webservice in Struts2 mittels des Restful2ActionMappers implementiert. Beide bekamen über Spring diverse Dienste injected. Zuerst hatten wir die ungewöhnlich große Größe der Post Requests und der Responses in Verdacht, jedoch schienen diese in Ordnung zu sein. Trotzdem häuften sich Variationen von:

java.io.IOException: CRLF expected at end of chunk: 72/84
java.io.IOException: Bad chunk size: somexml

Als uns klar wurde, daß das Problem auf dem Transportweg auftritt sahen wir uns um und entdeckten diese Spring Konfiguration:

<bean name="restClient" class="de.codecentric.framework.RestClient">
  <property name="httpClient">
    <bean class="org.apache.commons.httpclient.HttpClient" />
  </property>
</bean>

Standardmäßig hat der HttpClient einen ConnectionManager der immer die gleiche Connection herausgibt. Sogar an unterschiedliche Threads. Wenn man das einmal weiß, findet man schnell den

org.apache.commons.httpclient.MultiThreadedHttpConnectionManager

doch leider half dieser auch nicht weiter. Es gesellte sich eine

java.io.IOException: connection closed

hinzu. Was vielleicht überraschend klingt: der MultiThreadedHttpConnectionManager erlaubt per default nur 2 Verbindungen zum gleichen Host. Nachdem wir diese erhöhten lief die Anwendung auch wieder unter Last.

So ungefähr sieht dann die Spring Konfiguration aus:

<bean name="restClient" class="de.codecentric.framework.RestClient">
  <property name="httpClient">
    <bean class="org.apache.commons.httpclient.HttpClient">
      <property name="httpConnectionManager">
        <bean class="org.apache.commons.httpclient.MultiThreadedHttpConnectionManager" destroy-method="shutdown">
          <property name="params">
            <bean class="org.apache.commons.httpclient.params.HttpConnectionManagerParams">
              <property name="defaultMaxConnectionsPerHost" value="20" />
            </bean>
          </property>
        </bean>
      </property>
    </bean>
  </property>
</bean>

Fazit: Wenn sich verschiedene Threads die gleiche UrlConnection teilen geschehen die wundersamsten Dinge (Exceptions) :-)

Fabian Lange

 

Vergleich von Java und PHP für Webanwendungen

Keine andere Sprache sorgt seit langer Zeit für so kontroverse Diskussionen wie PHP. Als auf Java spezialisierte Firma erreichen die codecentric GmbH auch Anfragen zur Migration von PHP Anwendungen.

Dabei geht die Frage, ob Java besser als PHP sei, an dem Hauptproblem vorbei. Sowohl in Java als auch in PHP gibt es Frameworks, welche speziell das Erstellen von Web Anwendungen unterstützen. Frameworks können natürlich Nachteile von Sprachen ausgleichen, aber auch Vorteile von Sprachen negieren.

Um den Vergleich von Java und PHP zu verstehen muss man in der Zeit bis etwa in das Jahr 2000 zurückgehen. Java bot damals mit Servlets und Struts erste Konzepte für Web Anwendungen, aber diese zu erstellen, zu konfigurieren und zu deployen war sehr kompliziert. Durch den Boom des Internets entstand eine neue Entwicklergemeinschaft welche schnell HTML lernte. Doch reines HTML begrenzt die Möglichkeit an Interaktion und CGI-Perl Skripte waren umständlich und schwierig. PHP bot hingegen eine elegante und einfache Möglichkeit, wollte man ein Datum in einer Webseite ausgeben, so nannte man die Webseite nicht “.html” sondern “.php” und baute an der gewünschten Stelle ein <?php echo date() ?> ein. Auf dem Webserver Apache, welcher bereits für PHP vorbereitet war, lief die neue Datei sofort.

Zwar gab es auch in JavaServer Pages die Möglichkeit Scriptlets zu verwenden, doch dies war als unsauber verpönt. Stattdessen propagierte die Java Community die Verwendung von Komponenten. Meiner Meinung nach, ein entscheidender Faktor für die Kategorisierung von Java als “Enterprise”.

Für Internetanwendungen ist ein schönes Design wichtiger als ein Funktionales, da es mehr Kunden anzieht. Während ein in Dreamweaver oder Frontpage vom Designer gebautes HTML von PHP Entwicklern einfach mit dynamischer Funktionalität erweiterbar war, konnten komponentenbasierte Java Frameworks nicht viel damit anfangen. PHP konnte Designs mit Funktionalität ausstatten. In Java musste man jedoch die Funktionalität verschönern.

Doch in den vergangenen Jahren entstand Einsicht auf beiden Seiten. Java reduzierte die Komplexität, Frameworks wie Tapestry oder GWT, erlaubten von Designern erstellte Templates. PHP erlernte mit Version 5 brauchbare Objektorientierung und Frameworks wie Zend oder symfony brachten den PHP Entwicklern Designkonzepte bei. Auch die ergänzenden Bibliotheken von Java fanden Entsprechungen auf PHP Seite. So gibt es zum Beispiel in PHP die ORMs Propel und Doctrine.

Vom heutigen Standpunkt aus betrachtet bieten also Java und PHP ähnliche Funktionalität. Dennoch bleiben weitere Aspekte zu betrachten:

  • Stabilität
    PHP hat hier meiner Meinung nach deutliche Schwächen. Die prozedurale Abwärtskompatibilität, kein echter Deprecationmechanismus, ein undurchschaubarer Wirrwarr an halboffiziellen Bibliotheken und plattformabhängiger Funktionalität sind nur einige der Problempunkte die PHP hat. PHP mangelt es an einem sauberen Schnitt, den das PHP Team mit Version 6 geplant hat.
    Java hingegen hat eine saubere Platformunabhängigkeit und eine recht klar definierte Anzahl an Kernbibliotheken mit entsprechenden Qualitätsstandards.
  • Performance
    Wurde früher Java oft als langsam bezeichnet, so sind heute die JVMs hochoptimiert, wohingegen die Skriptsprachen, auch PHP noch damit kämpfen. So gibt es erst in PHP 5.3 einen brauchbaren Garbage Collector. Auch andere Optimierungen fanden nur sehr zögerlich Einzug in die PHP Runtimes. Dies mag wohl daran liegen, daß PHP im Gegensatz zu Java nach jedem Request die VM neu startet, was weitere Performanceprobleme bedingt. So muss bei jedem Request die Session von Platte gelesen werden. Zwar gibt es dort auch Lösungen im PHP Bereich (MemCache, APC), jedoch sind diese zum Einen selten eingesetzt, zum Anderen auch noch stark in der Entwicklung.
    Interessanterweise macht dieser Nachteil die Skalierung von PHP Anwendungen recht einfach. Da Requests völlig separat verarbeitet werden können, wirkt sich zusätzliche Hardware relativ linear auf die Kapazitäten des Servers aus. Im Web liegt der Fokus auch eher auf der Anzahl der Requests, nicht direkt auf der genauen Dauer eines einzelnen Requests.
  • Auswahl
    Idealerweise erfindet man das Rad nicht neu. Selbst wenn man es noch runder machen könnte steht der Aufwand auf einer holperigen Straße nicht in Relation zum Nutzen. Von daher ist es sinnvoll bereits existierenden Lösungen zu verwenden. Sowohl in PHP, als auch in Java existiert viel modularer Software, teils mit freien, teils mit unfreien Lizenzen. Allerdings haben PHP Module wesentlich mehr Probleme als in Java geschriebene. So haben einige PHP Modulentwickler sich eigene Konzepte einfallen lassen (z.B. Zend nutzt Zend Loader als Ersatz für Packages) oder die Module sind nur auf ein Framework optimiert (symfony Plug-In).
    Java ist als Sprache, gerade durch die “komplizierten Konzepte” wie z.b. Classloading und Packages, besser auf Modularisierung vorbereitet. Auch durch die bessere Toolunterstützung (Ant/Maven, Javadoc, JUnit) besitzen Java Frameworks leichter zu installierende, besser dokumentierte und getestete Artefakte. Allerdings verbreiten sich PHP Tools für diese Aufgaben (pake/phing, PHPDocumentor, PHPUnit/lime).
  • Integration
    Integration ist sicherlich die Stärke von Java. Zum einen ist Java selbst fast “Industry Standard”, zum anderen gibt es für viele Standards Implementierungen in Java. Soll eine PHP Webanwendung auf einem bestimmten Protokoll kommunizieren ist die Auswahl in PHP relativ dünn. Selbst größere Implementierungen sind z.B. von Zend sind teilweise nur sehr rudimentär implementiert (z.B. OpenID). Dies mag aber auch daran liegen, daß Integrationen von PHP Anwendungen oft über Datenbanken laufen.
  • Entwickler Know-How
    Schon vor 20 Jahren hat Frederic Brooks nach der “Silver Bullet” gesucht und sie nicht gefunden. In seinem Artikel kommt er zu dem Schluss, daß Softwaredesign, Problemformulierung und die Fähigkeiten der Entwickler wesentlich wichtiger sind als die verwandten Tools oder Sprachen. Von daher ist es sicherlich sinnvoller bei der Umsetzung einer Webpräsenz durch einen Designer mit PHP Kenntnissen ein aktuelles PHP Framework einzusetzen. Soll nur das Web-Frontend für ein Java EE Backend entwickelt werden ist sicherlich Java die näherliegende Wahl.
    Allerdings sollte das Entwicklerknowledge nicht primär im Fokus stehen. Gewisse Technologische Hürden lassen sich nur mit bestimmten anderen Technologien und Sprachen sinnvoll lösen, und es ist mitunter sinnvoller einen Experten mit spezifischen Fähigkeiten einzukaufen als es mit ungeeigneten Tools selbst zu versuchen.

Als Fazit bleibt mir der Schluss, daß Java weiterhin die bessere Wahl für viele Projekte ist. Für kleinere isolierte Projekte können aber Scriptsprachen schneller zum Ziel führen. Als Kompromiss vielleicht Groovy mit Grails?

Fabian Lange

 

XSL-Performance Tuning

In den letzten Tagen habe ich mich intensiv mit dem Tuning von XSLs beschäftigen dürfen, die innerhalb einer Web-Anwendung zur Erzeugung der HTML-Masken eingesetzt werden. Prinzipiell stellten die XSLs in diesem Fall kein Antwortzeit-Problem dar, jedoch verbrauchte eine XSL-Transformation einfach zu viel CPU. Dies wollten wir optimieren.

Nach ein wenig googlen habe ich dann festgestellt, dass das Thema XSL-Tuning im Vergleich zu Java-Tuning/-Profiling dünn besetzt ist. Die meisten Einträge sind schon relativ alt zu diesem Thema. Auch gibt es relativ wenige Werkzeuge, die man einsetzen kann. Es gibt zwar einige XSL-Profiler (z.B. Stylusstudio, Oxygen), jedoch war in unserem Fall die XSL-Transformation in einer Web-Anwendung vollständig eingebettet. Daher wollten wir nicht das dynamisch erzeugte XML in Dateien schreiben und dann einzelnd profilen. Einige XSLT-Implementierungen bieten selber schon Profiling-Informationen an, z.B. kann man bei Saxon einen entsprechenden Parameter setzen. Wir setzen Xalan ein und dort gibt es eine solche Option nicht.

Wir sind daher unseren “normalen” Weg gegangen, d.h. wir haben einen Java-Profiler benutzt und die Xalan-Klassen instrumentiert. Xalan (wenn XSLTC verwendet wird) generiert Bytecode für die XSLs zur Laufzeit (Translets), die wir ebenfalls profilen konnten. Im Profiler konnte man dann recht gut erkennen, welche Templates (bei Verwendung von includes/call-template/apply-templates) die meiste Zeit verbraucht haben und hatten dann entsprechende Ansatzpunkte, bei denen wir optimieren konnten.

Wir haben dabei festgestellt, dass XSL-Tuning grundlegendes Verständnis einer XSL-Transformation voraussetzt, d.h. nicht nur, welche XSL-Tags verwendet werden können und welche Alternativen es gibt, sondern insbesondere auch, wie ein XSL-Tag /XPath-Ausdrück funktioniert. So arbeitet eine XSL-Transformation grundsätzlich auf einem XML-Baum (auch wenn nicht alle XSLT-Implementierungen DOM benutzen und auch Xalan durch das eigene DTM optimiert) und alle Operationen zur Navigation innerhalb eines XML-Baums sind relativ teuer , z.B. “..”, “//” oder “descandant::”-Ausdrücke. Je nach Komplexität des XML-Baums konnte man hierdurch schon optimieren. Es hilft auch, diesen XML-Baum möglichst klein zu halten, d.h. Datenmenge zu reduzieren. Im Endeffekt waren es solche “Baumoperationen”, die wir weg-optimiert haben. Aus Performance-Sicht teuer war auch der Umgang mit “nodeset()”, diese Funktion haben wir benutzt selber nochmal innerhalb der XSL XML zu parsen….

Ansonsten haben wir auch einige andere Optimierungen probiert:

  1. Umsetzung der Maßnahmen aus den offiziellen Xalan-FAQs
  2. Austauschen von Xalan durch andere Implementierungen (z.B. Saxon)
  3. Auslagern von “teuren” Teilen in eigene Java-Implementierungen. Hier bietet Xalan Mechanismen für eigene Extensions

Auch bei XSL-Tuning gilt : Immer nur eine Maßnahme durchführen und dann nachmessen. Je nach XSL kann eine Maßnahme auch schlecht sein, daher vermeide ich hier auch generelle Regeln…

Wenn alles Tuning nicht helfen sollte, gibt es noch die Möglichkeit, die XSL-Transformation komplett auszulagern auf ein dafür optimiertes System (z.B. IBM Datapower, Layer7).  Hier haben wir die IBM Datapower getestet und diese hat die XSL-Transformation in einer wahnsinnigen Geschwindigkeit ausgeführt. Hier spielen natürlich andere Gründe eine Rolle, ob man eine solche Appliance einsetzen möchte.

Rainer Vehns

 

Nächste Seite »