Memantau Aplikasi Java dengan Flight Recorder

1. Ikhtisar

Dalam tutorial ini, kita akan memeriksa Java Flight Recorder, konsepnya, perintah dasarnya, dan cara menggunakannya.

2. Utilitas Pemantauan Java

Java bukan hanya bahasa pemrograman tetapi ekosistem yang sangat kaya dengan banyak alat. JDK berisi program yang memungkinkan kita untuk mengkompilasi program kita sendiri, serta memantau statusnya dan status Java Virtual Machine selama siklus hidup penuh dari eksekusi program.

The bin folder dari distribusi JDK berisi, antara lain, program-program berikut yang dapat digunakan untuk profil dan pemantauan:

  • Java VisualVM (jvisualvm.exe)
  • JConsole (jconsole.exe)
  • Kontrol Misi Java (jmc.exe)
  • Alat Perintah Diagnostik (jcmd.exe)

Kami menyarankan untuk menjelajahi konten folder ini untuk mengetahui alat apa yang kami miliki. Harap dicatat bahwa Java VisualVM adalah bagian dari Oracle dan Open JDK distribusi di masa lalu. Namun, mulai dari Java 9, distribusi JDK tidak lagi dikirimkan dengan VisualVM Java . Oleh karena itu, kami harus mengunduhnya secara terpisah dari situs web proyek sumber terbuka VisualVM.

Dalam tutorial ini, kami akan fokus pada Java Flight Recorder. Ini tidak ada di antara alat yang disebutkan di atas karena ini bukan program yang berdiri sendiri. Penggunaannya terkait erat dengan dua alat di atas - Java Mission Control dan Alat Perintah Diagnostik.

3. Java Flight Recorder dan Konsep Dasarnya

Java Flight Recorder (JFR) adalah alat pemantauan yang mengumpulkan informasi tentang kejadian di Java Virtual Machine (JVM) selama pelaksanaan aplikasi Java . JFR adalah bagian dari distribusi JDK, dan terintegrasi ke dalam JVM.

JFR dirancang untuk sesedikit mungkin memengaruhi kinerja aplikasi yang sedang berjalan .

Untuk menggunakan JFR, kita harus mengaktifkannya. Kami dapat mencapai ini dengan dua cara:

  1. saat memulai aplikasi Java
  2. meneruskan perintah diagnostik alat jcmd saat aplikasi Java sudah berjalan

JFR tidak memiliki alat mandiri. Kami menggunakan Java Mission Control (JMC), yang berisi plugin yang memungkinkan kami untuk memvisualisasikan data yang dikumpulkan oleh JFR.

Ketiga komponen ini - JFR , jcmd dan JMC - membentuk rangkaian lengkap untuk mengumpulkan informasi runtime tingkat rendah dari program Java yang sedang berjalan. Kami mungkin menemukan informasi ini sangat berguna saat mengoptimalkan program kami, atau saat mendiagnosisnya jika terjadi kesalahan.

Jika kami memiliki berbagai versi Java yang diinstal di komputer kami, penting untuk memastikan bahwa compiler Java ( javac ), Java launcher ( java ), dan alat yang disebutkan di atas (JFR, jcmd, dan JMC) berasal dari distribusi Java yang sama . Jika tidak, ada risiko tidak dapat melihat data yang berguna karena format data JFR dari versi yang berbeda mungkin tidak kompatibel.

JFR memiliki dua konsep utama: peristiwa dan aliran data. Mari kita bahas secara singkat.

3.1. Acara

JFR mengumpulkan peristiwa yang terjadi di JVM saat aplikasi Java dijalankan. Peristiwa ini terkait dengan status JVM itu sendiri atau status program. Peristiwa memiliki nama, stempel waktu, dan informasi tambahan (seperti informasi utas, tumpukan eksekusi, dan status heap).

Ada tiga jenis peristiwa yang dikumpulkan JFR:

  • peristiwa instan dicatat segera setelah itu terjadi
  • peristiwa durasi dicatat jika durasinya berhasil mencapai ambang batas yang ditentukan
  • acara sampel digunakan untuk mengambil sampel aktivitas sistem

3.2. Aliran data

Peristiwa yang dikumpulkan JFR mengandung sejumlah besar data. Untuk alasan ini, secara desain, JFR cukup cepat untuk tidak menghalangi program.

JFR menyimpan data tentang kejadian dalam satu file keluaran, flight.jfr.

Seperti yang kita ketahui, operasi I / O disk cukup mahal. Oleh karena itu, JFR menggunakan berbagai buffer untuk menyimpan data yang dikumpulkan sebelum membuang blok data ke disk. Hal-hal mungkin menjadi sedikit lebih kompleks karena, pada saat yang sama, sebuah program mungkin memiliki beberapa proses pendaftaran dengan opsi berbeda.

Karena itu, kami mungkin menemukan lebih banyak data dalam file keluaran daripada yang diminta, atau mungkin tidak dalam urutan kronologis . Kami bahkan mungkin tidak memperhatikan fakta ini jika kami menggunakan JMC, karena JMC memvisualisasikan peristiwa dalam urutan kronologis.

Dalam beberapa kasus yang jarang terjadi, JFR mungkin gagal untuk membersihkan data (misalnya, ketika ada terlalu banyak acara atau dalam kasus pemadaman listrik). Jika ini terjadi, JFR mencoba memberi tahu kami bahwa file keluaran mungkin kehilangan sebagian data.

4. Cara Menggunakan Java Flight Recorder

JFR adalah fitur eksperimental, oleh karena itu penggunaannya dapat berubah. Padahal, di distro sebelumnya, kita harus mengaktifkan fitur komersial agar bisa digunakan dalam produksi. Namun, mulai dari JDK 11, kami dapat menggunakannya tanpa mengaktifkan apa pun. Kami selalu dapat melihat catatan rilis resmi Java untuk mengetahui cara menggunakan alat ini.

Untuk JDK 8, agar dapat mengaktifkan JFR, kita harus memulai JVM dengan opsi + UnlockCommercialFeatures dan + FlightRecorder .

Seperti yang telah kami sebutkan di atas, ada dua cara untuk mengaktifkan JFR. Saat kami mengaktifkannya secara bersamaan dengan memulai aplikasi, kami melakukannya dari baris perintah. Saat aplikasi sudah berjalan, kami menggunakan alat perintah diagnostik.

4.1. Garis komando

Pertama, kami mengompilasi file * .java program menjadi * .class menggunakan kompilator java standar javac .

Setelah kompilasi berhasil, kita dapat memulai program dengan opsi berikut:

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

di mana path-to-class-file adalah titik masuk aplikasi * .class file.

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.

Seperti biasa, potongan kode tersedia di repositori Github kami.