Surveillance des applications Java avec Flight Recorder

1. Vue d'ensemble

Dans ce didacticiel, nous examinerons Java Flight Recorder, ses concepts, ses commandes de base et comment l'utiliser.

2. Utilitaires de surveillance Java

Java n'est pas seulement un langage de programmation mais un écosystème très riche avec de nombreux outils. Le JDK contient des programmes qui nous permettent de compiler nos propres programmes, ainsi que de surveiller leur état et l'état de la machine virtuelle Java pendant le cycle de vie complet de l'exécution du programme.

Le dossier bin d'une distribution JDK contient, entre autres, les programmes suivants qui peuvent être utilisés pour le profilage et la surveillance:

  • Java VisualVM (jvisualvm.exe)
  • JConsole (jconsole.exe)
  • Contrôle de mission Java (jmc.exe)
  • Outil de commande de diagnostic (jcmd.exe)

Nous vous suggérons d'explorer le contenu de ce dossier pour connaître les outils dont nous disposons. Veuillez noter que Java VisualVM faisait partie des distributions Oracle et Open JDK dans le passé. Cependant, à partir de Java 9, les distributions JDK ne sont plus livrées avec Java VisualVM . Par conséquent, nous devons le télécharger séparément du site Web du projet open source VisualVM.

Dans ce didacticiel, nous nous concentrerons sur l'enregistreur de vol Java. Ce n'est pas présent parmi les outils mentionnés ci-dessus car ce n'est pas un programme autonome. Son utilisation est étroitement liée à deux des outils ci-dessus - Java Mission Control et Diagnostic Command Tools.

3. Java Flight Recorder et ses concepts de base

Java Flight Recorder (JFR) est un outil de surveillance qui collecte des informations sur les événements dans une machine virtuelle Java (JVM) pendant l'exécution d'une application Java . JFR fait partie de la distribution JDK, et il est intégré à la JVM.

JFR est conçu pour affecter le moins possible les performances d'une application en cours d'exécution .

Pour utiliser JFR, nous devons l'activer. Nous pouvons y parvenir de deux manières:

  1. lors du démarrage d'une application Java
  2. transmission des commandes de diagnostic de l' outil jcmd lorsqu'une application Java est déjà en cours d'exécution

JFR n'a pas d'outil autonome. Nous utilisons Java Mission Control (JMC), qui contient un plugin qui nous permet de visualiser les données collectées par JFR.

Ces trois composantes - JFR , jcmd et JMC - forment une suite complète pour la collecte d' informations d'exécution à faible niveau d'un programme Java en cours d' exécution. Nous pouvons trouver ces informations très utiles lors de l'optimisation de notre programme, ou lors du diagnostic en cas de problème.

Si nous avons différentes versions de Java installées sur notre ordinateur, il est important de s'assurer que le compilateur Java ( javac ), le lanceur Java ( java ) et les outils mentionnés ci-dessus (JFR, jcmd et JMC) proviennent de la même distribution Java . Sinon, il y a un risque de ne pas pouvoir voir de données utiles car les formats de données JFR des différentes versions pourraient ne pas être compatibles.

JFR a deux concepts principaux: les événements et le flux de données. Discutons-en brièvement.

3.1. Événements

JFR collecte les événements qui se produisent dans la JVM lors de l'exécution de l'application Java. Ces événements sont liés à l'état de la JVM elle-même ou à l'état du programme. Un événement a un nom, un horodatage et des informations supplémentaires (comme les informations de thread, la pile d'exécution et l'état du tas).

Il existe trois types d'événements que JFR collecte:

  • un événement instantané est enregistré immédiatement une fois qu'il se produit
  • un événement de durée est enregistré si sa durée atteint un seuil spécifié
  • un exemple d'événement est utilisé pour échantillonner l'activité du système

3.2. Flux de données

Les événements que JFR collecte contiennent une énorme quantité de données. Pour cette raison, de par sa conception, JFR est suffisamment rapide pour ne pas gêner le programme.

JFR enregistre les données sur les événements dans un seul fichier de sortie, flight.jfr.

Comme nous le savons, les opérations d'E / S disque sont assez coûteuses. Par conséquent, JFR utilise divers tampons pour stocker les données collectées avant de vider les blocs de données sur le disque. Les choses peuvent devenir un peu plus complexes car, au même moment, un programme peut avoir plusieurs processus d'enregistrement avec des options différentes.

Pour cette raison, nous pouvons trouver plus de données dans le fichier de sortie que demandé, ou il peut ne pas être dans l'ordre chronologique . Nous pourrions même ne pas remarquer ce fait si nous utilisons JMC, car il visualise les événements dans l'ordre chronologique.

Dans certains cas rares, JFR peut ne pas vider les données (par exemple, lorsqu'il y a trop d'événements ou en cas de panne de courant). Si cela se produit, JFR essaie de nous informer que le fichier de sortie peut manquer un élément de données.

4. Comment utiliser Java Flight Recorder

JFR est une fonctionnalité expérimentale, son utilisation est donc sujette à changement. En fait, dans les distributions précédentes, nous devons activer des fonctionnalités commerciales pour pouvoir l'utiliser en production. Cependant, à partir du JDK 11, nous pouvons l'utiliser sans rien activer. Nous pouvons toujours consulter les notes de version officielles de Java pour vérifier comment utiliser cet outil.

Pour JDK 8, pour pouvoir activer JFR, nous devons démarrer la JVM avec les options + UnlockCommercialFeatures et + FlightRecorder .

Comme nous l'avons mentionné ci-dessus, il existe deux façons d'activer JFR. Lorsque nous l'activons simultanément au démarrage de l'application, nous le faisons à partir de la ligne de commande. Lorsque l'application est déjà en cours d'exécution, nous utilisons l'outil de commande de diagnostic.

4.1. Ligne de commande

Tout d'abord, nous compilons le fichier * .java du programme dans une * .class en utilisant le compilateur java standard javac .

Une fois la compilation réussie, nous pouvons démarrer le programme avec les options suivantes:

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

chemin-vers-fichier-classe est le fichier * .class du point d'entrée de l'application .

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.

Comme toujours, l'extrait de code est disponible sur notre référentiel Github.