Analyse der CPU-Auslastung von Threads einer Java-Anwendung

Dieser Techblog Beitrag beschreibt einen ersten schnellen Analyseansatz, um der Ursache für eine erhöhte CPU-Auslastung auf die Spur zu kommen.

Krankt eine Java-Anwendung an Performanceproblemen oder sporadischer CPU-Überlastung, so wird schnell der Ruf einer entsprechenden Analyse der Ursache laut. Auf den ersten Blick kann man zwar die gesamte CPU-Belastung der Java-Anwendung beispielsweise mittels "top" unter Linux oder dem "Taskmanager" unter Windows feststellen, aber die Ermittlung der entsprechenden CPU konsumierenden Funktion innerhalb der "Black-Box" Java bleibt dem Betrachter verborgen.

Mit Threaddumps erhält man eine Übersicht des Ablaufverhaltens der Java-Anwendung zu einem bestimmten Zeitpunkt. Eine Zuordnung von Funktion zu CPU-Verbrauch ist in den nebenläufigen Java-Prozessen mit mehreren Threads damit jedoch nicht möglich. Eine Brücke schlägt hier das Kommando "ps" (Process-Status) unter Linux bzw. das Programm ProcessExplorer in Windows Betriebssystemen mit denen eine Anzeige der Threads und deren jeweiligen CPU-Verbrauch sichtbar wird.

Hat man einmal den Hauptprozess der Java-Anwendung identifiziert:

Unter Linux z.B. mit:
ps -ef | grep java

Unter Windows im ProcessExplorer:

Analyse der CPU-Auslastung von Threads einer Java-Anwendung

kann man sich für diesen Hauptprozess alle Javaprogramm-internen Threads und deren CPU-Verbrauch anzeigen lassen:

Unter Linux mit:
ps -eLo pid,lwp,pcpu | grep <PID_des_Java_Prozesses>

unter Windows im ProcessExplorer über "rechte Maustaste" => "Properties" / "Eigenschaften" im Tab: "Threads":

Analyse der CPU-Auslastung von Threads einer Java-Anwendung

Mit dieser Erkenntnis möchte man nun wissen, was dieser Thread genau macht, um zu verstehen, warum die zuvor gemessene Menge an CPU-Leistung verbraucht wird. Hierzu dient der Threaddump, welcher folgendermaßen erstellt wird:
jstack > threaddump1

Tipp: In der Regel sollten mehrere Threaddumps erstellt werden (häufig im Intervall von 10 Sekunden), um eine tatsächliche Aussage über das Langzeitverhalten treffen zu können.

Ist der Threaddump erstellt, erhält man ein momentanes Abbild der Tätigkeiten des Java-Programmes.

Im letzten Schritt muss einzig eine Umrechnung der Thread-IDs aus dem dezimalen Zahlensystem (aus den Prozessüberwachungswerkzeugen) in das Hexadezimale Format ("nid" = "Native Thread ID" im Threaddump) erfolgen, um eine Querverbindung zu den Funktionsaufrufen im Threaddump herstellen zu können. Dies gelingt unter Linux mit dem Befehl:

echo "obase=16; 5544" | bc
15A8

unter Windows kann dies z.B. mit der "Programmierer-Ansicht" des Taschenrechners erfolgen.

Mit dieser Hexadezimalen Zahl kann nun im Threaddump gesucht und die entsprechende "nid" gefunden werden. Der nachfolgende Auszug aus einem Threaddump zeigt die Ursache für die erhöhte CPU-Auslastung des Threads mit der "nid: 0x15A8". In diesem Beispiel wird in der Atlassian Anwendung Confluence in diesem einzelnen Thread ein Hintergrundjob "Back Up Confluence" ausgeführt, der im Moment der Threaddump-Erstellung die Plugins sichert und dabei rund 10% der CPU-Leistung verbraucht, siehe Screenshot von dem ProcessExplorer oben.

Analyse der CPU-Auslastung von Threads einer Java-Anwendung

Fazit: Dieser Techblog Beitrag beschreibt einen ersten schnellen Analyseansatz, um der Ursache für eine erhöhte CPU-Auslastung auf die Spur zu kommen. Hat man über die Prozessanalyse einmal den CPU-konsumierenden Thread gefunden, kann dieser anschließend über die Threaddumps hinsichtlich der zugehörigen problemverursachenden Programmabläufe untersucht werden.

Bill Martin
06. April 2017 

Sie haben Fragen oder möchten sich von uns beraten lassen?

Gerne stehen wir für Ihre Fragen zur Verfügung. Nutzen Sie einfach unser Kontaktformular.