Profilierung von Java-Code: Engpässe in der Praxis finden
Jeder Java-Entwickler stößt früher oder später auf Leistungsprobleme: Die Anwendung läuft langsam, verbraucht zu viel Speicher oder friert unerwartet ein. In solchen Situationen kommt man an der Profilierung nicht vorbei. In diesem Artikel schauen wir uns an, wie man mit modernen Profilierungswerkzeugen Engpässe in Java-Code praktisch findet.
Was ist Profilierung und warum wird sie benötigt?
Profilierung (profiling) ist eine dynamische Analyse eines Programms, die Daten über dessen Betrieb sammelt: CPU-Auslastung, Speichernutzung, Ausführungszeit von Methoden, Anzahl erstellter Objekte und Threads. Im Gegensatz zum Logging liefert die Profilierung ein genaues Bild der "Engpässe", ohne manuell Timer setzen zu müssen.
Die wichtigsten Arten der Profilierung:
- CPU-Profilierung – ermittelt, welche Methoden die meiste Prozessorzeit verbrauchen.
- Memory-Profilierung – deckt Speicherlecks, die Häufigkeit der Objekterstellung und die Arbeit des Garbage Collectors (GC) auf.
- Thread-Profilierung – analysiert Sperren, Deadlocks und den Zustand von Threads.
Werkzeuge zur Java-Profilierung
Betrachten wir drei der beliebtesten Werkzeuge, die Ihnen helfen, Engpässe zu finden.
1. VisualVM
Ein kostenloses Werkzeug, das im JDK enthalten ist. Es eignet sich hervorragend für die schnelle Analyse einer laufenden Anwendung. Es ermöglicht die Überwachung von CPU, Speicher, Threads und sogar die Erstellung von Heap-Dumps.
// VisualVM von der Kommandozeile startenjvisualvm.exe2. JProfiler
Ein kommerzieller Profiler mit einem leistungsstarken Funktionsumfang: detaillierte Analyse von CPU, Speicher, JDBC, JPA und SQL-Abfragen. Ideal für Enterprise-Anwendungen.
3. Java Flight Recorder (JFR) + JDK Mission Control
Ein in die JVM integriertes Werkzeug (verfügbar ab Java 11). Es sammelt Low-Level-Ereignisse ohne signifikante Leistungseinbußen. Empfohlen für Production-Umgebungen.
// JFR-Aufzeichnung für 60 Sekundenjcmd <PID> JFR.start duration=60s filename=recording.jfrPraktisches Beispiel: Einen Engpass finden
Angenommen, wir haben eine Anwendung, die eine Liste von Benutzern verarbeitet und Berichte erstellt. Sie läuft langsam. Schreiben wir einen einfachen Testcode und profilieren ihn mit VisualVM.
Schritt 1: Code vorbereiten
import java.util.ArrayList;import java.util.List;
public class SlowApp { public static void main(String[] args) { List<String> users = new ArrayList<>(); for (int i = 0; i < 100000; i++) { users.add("User" + i); } processUsers(users); }
public static void processUsers(List<String> users) { for (String user : users) { String report = generateReport(user); // Speichern simulieren System.out.println(report.length()); } }
public static String generateReport(String user) { StringBuilder sb = new StringBuilder(); for (int i = 0; i < 1000; i++) { sb.append(user).append(" - data ").append(i).append(""); } return sb.toString(); }}Schritt 2: Profilierung starten
Starten Sie die Anwendung und öffnen Sie VisualVM. Wählen Sie den Prozess im linken Bereich aus, wechseln Sie zum Tab "Profiler" und klicken Sie auf "CPU", um die Profilierung zu starten.
Schritt 3: Ergebnisse analysieren
Nach dem Stoppen der Profilierung sehen Sie eine Tabelle mit Methoden, sortiert nach der benötigten Zeit. In unserem Beispiel wird die Methode generateReport ganz oben stehen – sie verbraucht über 90% der CPU-Zeit aufgrund der String-Verkettung in der Schleife.
Schritt 4: Optimierung
Ersetzen wir StringBuilder durch einen vorab zugewiesenen Puffer:
Blogs
Buchempfehlungen
Lesen Sie auch
Der ternäre Operator in Kotlin: 5 Hauptfehler von Anfängern
Fehler @Override in Eclipse: So besiegen Sie "Must Override a Superclass Method"
Arbeit mit WebAssembly und Go: Von A bis Z – Vollständiger Leitfaden
Wie Node.js Befehlszeilenargumente verarbeitet: von process.argv bis zu den Quellen
Reguläre Ausdrücke in Java mit Beispielen: Vollständiger Leitfaden