Überwachen von Java-Anwendungen mit Flight Recorder

1. Übersicht

In diesem Tutorial werden wir Java Flight Recorder, seine Konzepte, seine grundlegenden Befehle und seine Verwendung untersuchen.

2. Java Monitoring Utilities

Java ist nicht nur eine Programmiersprache, sondern ein sehr reichhaltiges Ökosystem mit vielen Tools. Das JDK enthält Programme, mit denen wir unsere eigenen Programme kompilieren sowie deren Status und den Status der Java Virtual Machine während des gesamten Lebenszyklus der Programmausführung überwachen können.

Der bin- Ordner einer JDK-Distribution enthält unter anderem die folgenden Programme, die zur Profilerstellung und Überwachung verwendet werden können:

  • Java VisualVM (jvisualvm.exe)
  • JConsole (jconsole.exe)
  • Java Mission Control (jmc.exe)
  • Diagnosebefehlstool (jcmd.exe)

Wir empfehlen, den Inhalt dieses Ordners zu untersuchen, um zu erfahren, über welche Tools wir verfügen. Beachten Sie, dass Java VisualVM in der Vergangenheit Teil der Oracle- und Open JDK-Distributionen war. Jedoch ausgehend von Java 9, JDK - Distributionen nicht mehr Schiff mit Java VisualVM . Daher sollten wir es separat von der Open Source-Projektwebsite von VisualVM herunterladen.

In diesem Tutorial konzentrieren wir uns auf den Java Flight Recorder. Dies ist bei den oben genannten Tools nicht vorhanden, da es sich nicht um ein eigenständiges Programm handelt. Die Verwendung hängt eng mit zwei der oben genannten Tools zusammen - Java Mission Control und Diagnostic Command Tools.

3. Java Flight Recorder und seine Grundkonzepte

Java Flight Recorder (JFR) ist ein Überwachungstool, das Informationen zu den Ereignissen in einer Java Virtual Machine (JVM) während der Ausführung einer Java-Anwendung sammelt . JFR ist Teil der JDK-Distribution und in die JVM integriert.

JFR wurde entwickelt, um die Leistung einer laufenden Anwendung so wenig wie möglich zu beeinträchtigen .

Um JFR verwenden zu können, sollten wir es aktivieren. Wir können dies auf zwei Arten erreichen:

  1. beim Starten einer Java-Anwendung
  2. Übergeben von Diagnosebefehlen des jcmd- Tools, wenn bereits eine Java-Anwendung ausgeführt wird

JFR verfügt nicht über ein eigenständiges Tool. Wir verwenden Java Mission Control (JMC), das ein Plugin enthält, mit dem wir die von JFR gesammelten Daten visualisieren können.

Diese drei Komponenten - JFR , jcmd und JMC - bilden eine vollständige Suite zum Sammeln von Laufzeitinformationen auf niedriger Ebene eines laufenden Java-Programms. Wir können diese Informationen sehr nützlich finden, wenn wir unser Programm optimieren oder diagnostizieren, wenn etwas schief geht.

Wenn auf unserem Computer verschiedene Java-Versionen installiert sind, müssen Sie sicherstellen, dass der Java-Compiler ( javac ), der Java-Launcher ( java ) und die oben genannten Tools (JFR, jcmd und JMC) aus derselben Java-Distribution stammen . Andernfalls besteht die Gefahr, dass keine nützlichen Daten angezeigt werden, da die JFR-Datenformate verschiedener Versionen möglicherweise nicht kompatibel sind.

JFR hat zwei Hauptkonzepte: Ereignisse und Datenfluss. Lassen Sie uns sie kurz diskutieren.

3.1. Veranstaltungen

JFR sammelt Ereignisse, die in der JVM auftreten, wenn die Java-Anwendung ausgeführt wird. Diese Ereignisse hängen mit dem Status der JVM selbst oder dem Status des Programms zusammen. Ein Ereignis hat einen Namen, einen Zeitstempel und zusätzliche Informationen (wie Thread-Informationen, Ausführungsstapel und Status des Heaps).

Es gibt drei Arten von Ereignissen , die JFR sammelt:

  • Ein sofortiges Ereignis wird sofort protokolliert, sobald es auftritt
  • Ein Dauerereignis wird protokolliert, wenn seine Dauer einen bestimmten Schwellenwert erreicht
  • Ein Beispielereignis wird verwendet, um die Systemaktivität abzutasten

3.2. Datenfluss

Die Ereignisse, die JFR sammelt, enthalten eine große Datenmenge. Aus diesem Grund ist JFR von Natur aus schnell genug, um das Programm nicht zu behindern.

JFR speichert Daten zu den Ereignissen in einer einzigen Ausgabedatei, flight.jfr.

Wie wir wissen, sind Festplatten-E / A-Vorgänge ziemlich teuer. Daher verwendet JFR verschiedene Puffer, um die gesammelten Daten zu speichern, bevor die Datenblöcke auf die Festplatte geleert werden. Die Dinge könnten etwas komplexer werden, weil ein Programm gleichzeitig mehrere Registrierungsprozesse mit unterschiedlichen Optionen haben könnte.

Aus diesem Grund finden wir möglicherweise mehr Daten in der Ausgabedatei als angefordert oder nicht in chronologischer Reihenfolge . Wir werden diese Tatsache möglicherweise nicht einmal bemerken, wenn wir JMC verwenden, da es die Ereignisse in chronologischer Reihenfolge visualisiert.

In einigen seltenen Fällen kann es sein, dass JFR die Daten nicht löscht (z. B. bei zu vielen Ereignissen oder bei einem Stromausfall). In diesem Fall versucht JFR, uns darüber zu informieren, dass in der Ausgabedatei möglicherweise Daten fehlen.

4. Verwendung von Java Flight Recorder

JFR ist ein experimentelles Merkmal, daher kann sich seine Verwendung ändern. Tatsächlich müssen wir in früheren Distributionen kommerzielle Funktionen aktivieren, um sie in der Produktion verwenden zu können. Ab JDK 11 können wir es jedoch verwenden, ohne etwas zu aktivieren. Wir können jederzeit die offiziellen Java-Versionshinweise konsultieren, um zu überprüfen, wie dieses Tool verwendet wird.

Damit JDK 8 JFR aktivieren kann, sollten wir die JVM mit den Optionen + UnlockCommercialFeatures und + FlightRecorder starten .

Wie oben erwähnt, gibt es zwei Möglichkeiten, JFR zu aktivieren. Wenn wir es gleichzeitig mit dem Starten der Anwendung aktivieren, tun wir dies über die Befehlszeile. Wenn die Anwendung bereits ausgeführt wird, verwenden wir das Diagnosebefehlstool.

4.1. Befehlszeile

Zuerst kompilieren wir die * .java- Datei des Programms mit dem Standard-Java-Compiler javac in eine * .class .

Sobald die Kompilierung erfolgreich ist, können wir das Programm mit den folgenden Optionen starten:

java -XX:+UnlockCommercialFeatures -XX:+FlightRecorder -XX:StartFlightRecording=duration=200s,filename=flight.jfr path-to-class-file

Dabei ist der Pfad zur Klassendatei der Einstiegspunkt der Anwendung * .class- Datei.

This command launches the application and activates the recording, which starts immediately and lasts no more than 200 seconds. Collected data is saved in an output file, flight.jfr. We'll describe the other options in more detail in the next section.

4.2. Diagnostic Command Tool

We can also start registering the events by using the jcmd tool. For example:

jcmd 1234 JFR.start duration=100s filename=flight.jfr

Prior to JDK 11, in order to be able to activate JFR in this way, we should start the application with unlocked commercial features:

java -XX:+UnlockCommercialFeatures -XX:+FlightRecorder -cp ./out/ com.baeldung.Main

Once the application is running, we use its process id in order to execute various commands, which take the following format:

jcmd   [parameters]

Here's a complete list of the diagnostic commands:

  • JFR.start – starts a new JFR recording
  • JFR.check – checks running JFR recording(s)
  • JFR.stop – stops a specific JFR recording
  • JFR.dump – copies contents of a JFR recording to file

Each command has a series of parameters. For example, the JFR.start command has the following parameters:

  • name – the name of the recording; it serves to be able to reference this recording later with other commands
  • delay – dimensional parameter for a time delay of recording start, the default value is 0s
  • duration – dimensional parameter for a time interval of the duration of the recording; the default value is 0s, which means unlimited
  • filename – the name of a file that contains the collected data
  • maxage – dimensional parameter for the maximum age of collected data; the default value is 0s, which means unlimited
  • maxsize – the maximum size of buffers for collected data in bytes; the default value is 0, which means no max size

We've already seen an example of the usage of these parameters at the beginning of this section. For the complete list of the parameters, we may always consult the Java Flight Recorded official documentation.

Although JFR is designed to have as little of a footprint as possible on the performance of the JVM and the application, it's better to limit the maximum amount of collected data by setting at least one of the parameters: duration, maxage, or maxsize.

5. Java Flight Recorder in Action

Let's now demonstrate JFR in action by using an example program.

5.1. Example Program

Our program inserts objects into a list until an OutOfMemoryError occurs. Then the program sleeps for one second:

public static void main(String[] args) { List items = new ArrayList(1); try { while (true){ items.add(new Object()); } } catch (OutOfMemoryError e){ System.out.println(e.getMessage()); } assert items.size() > 0; try { Thread.sleep(1000); } catch (InterruptedException e) { System.out.println(e.getMessage()); } }

Without executing this code, we can spot a potential drawback: the while loop will lead to high CPU and memory usage. Let's use JFR to see these drawbacks and probably find others.

5.2. Start Registering

First, we compile our program by executing the following command from the command line:

javac -d out -sourcepath src/main src/main/com/baeldung/flightrecorder/FlightRecorder.java

At this point, we should find a file FlightRecorder.class in the out/com/baeldung/flightrecorder directory.

Now, we'll start the program with the following options:

java -XX:+UnlockCommercialFeatures -XX:+FlightRecorder -XX:StartFlightRecording=duration=200s,filename=flight.jfr -cp ./out/ com.baeldung.flightrecorder.FlightRecorder

5.3. Visualize Data

Now, we feed the file flight.jfr to Java Mission Control, which is part of the JDK distribution. It helps us visualize the data about our events in a nice and intuitive way.

Its main screen shows us the information about how the program was using the CPU during its execution. We see that the CPU was loaded heavily, which is quite expected due to the while loop:

On the left side of the view, we see sections General, Memory, Code, and Threads, among others. Each section contains various tabs with detailed information. For example, tab Hot Methods of section Code contains the statistics of method calls:

In this tab, we can spot another drawback of our example program: method java.util.ArrayList.grow(int) has been called 17 times in order to enlarge the array capacity every time there wasn't enough space for adding an object.

In more realistic programs, we may see a lot of other useful information:

  • statistics about created objects, when they were created and destroyed by the garbage collector
  • a detailed report about the threads' chronology, when they were locked or active
  • which I/O operations the application was executing

6. Conclusion

In this article, we introduced the topic of monitoring and profiling a Java application using Java Flight Recorder. This tool remains an experimental one, so we should consult its official site for more complete and recent information.

Wie immer ist das Code-Snippet in unserem Github-Repository verfügbar.