JDK Mission Control/Flight Recorder - introduction

It is an 0pen-source client tools suite that helps finding an issues and optimizing programs running on Java Virtual Machine (JVM). JDK Mission Control (JMC) has been open sourced in 2018. Such step enabled an individual  JDK Mission Control/Flight Recorder development independently on development of the Java Development Kit (JDK). It means since Java SE 11 everyone can troubleshoot a Java application “without” difficulties.

JDK Mission Control consists of two main tools:

  1. A Java Flight Recorder
  2. A JMX Console

Standard Java Development Kit (JDK) contains:

1. JCMD Utility ( jmcd sends diagnostic command to the JVM)

This tutorials provides an overview how to start using the JDK Flight Recorder to collect and analyze a low level information provided by Java Virtual Machine (JVM) at the runtime. Such information reside in the collected events (see bellow). JDK Mission Control stand-alone app allows to examine JFR recordings from the running Java application. The Java Flight Recorder (JFR)  is designed to affected the runtime as less as possible. Normally published number is less than 1% in general.

What is JDK Flight Recorder

JDK Flight Recorder is a profiling tool used to collect a diagnostic and profiling events from the running Java application. It has been already mentioned above that it has very small application performance penalty. JFR may extremely shorten a findings, inside a fault applications,  due to ability to observe an anomaly since its first emergence till the end of the application life cycle. JFR doesn’t have any stand-alone client it is available as a part of Mission Control application. JFR collect through the event an information about Threads, GC cycles, locks, sockets, memory and etc.

What are JDK Flight Recorder Events

There are few types of default events (Marcus Hirt blog):

  1. Instant: only time of event occurrence
  2. Request-able: configurable time period
  3. Duration: provide start and end time, duration
  4. Timed event: similar to duration events with configurable threshold.

Of course, there is a possibility to create a custom events, but this is out of the scope of current tutorial.

The collected events are stored in the external single output file .jfr. Such events chunks are stored into the file through the various buffers to eliminate the cost of I/O operations. It is important to mention that such chunks of events are not chronologically ordered but JFR displays them chronologically.

How to start JDK Flight Recorder

The JDK Mission Control was a part of the JDK for very long time, till the version 10. It means the “jmc” command resided in $JAVA_HOME/bin folder. For JDK 8 is one more step required, namely the application requires to have enabled  a commercial features (attention required). Enabling features can be done in following ways:

  • JVM paramaters : -XX:+UnlockCommercialFeatures (JDK 8), -XX:+FlightRecorder (JDKs 8,9,10)
  • JCMD Utility

The JDK Flight Recorder is integrated into the JDK since the Java SE 11 release (java versions: JEP-328), and no additional action is required to enable emitting the events. 

It’s recommended and important to consider to run a similar versions of Java SE when the tools JMC, JFR and jcmd are used. There is a possible risk of data-format inconsistency due to data format incompatibility.

The JDK Mission Control/Flight Recorder application can be downloaded from official release binaries providers (see bellow). There is also great tutorial how to run JDK Mission Control/Flight Recorder from sources (GitHub JMC). In this a tutorial the OpenJDK Mission Control/Flight Recorder build from sources is used.

The JDK Mission Control application is ready to run:

JDK Mission Control

Creating a JFR Readings

For the tutorial purposes the example Spring-Boot application “wits-vehicle-factory” has been created. 

$ jar --file=./vehicle-factory-main-1.0-SNAPSHOT.jar --describe-module
requires java.annotation
requires java.base mandated
requires spring.web
requires vehicle.factory.api
requires vehicle.factory.persistence
qualified opens com.wengnerits.example.spring.vehicles.factory to spring.beans spring.context spring.core
qualified opens com.wengnerits.example.spring.vehicles.factory.component to spring.beans spring.context spring.core

The application runs on Java SE 15 with preview features and uses Java Modules and Maven Modules (see: Java Platform Module System). The application also uses various data resources (not important)

Let’s start it:

$java --enable-preview -jar ./vehicle-factory-main-1.0-SNAPSHOT.jar                                        
                                                                                                                                                                            .   ____          _            __ _ _                                                                                                                                   
 /\\ / ___'_ __ _ _(_)_ __  __ _ \ \ \ \                                                                                                                                  
( ( )\___ | '_ | '_| | '_ \/ _` | \ \ \ \                                                                                                                                 
 \\/  ___)| |_)| | | | | || (_| |  ) ) ) )                                                                                                                                
  '  |____| .__|_| |_|_| |_\__, | / / / /
 :: Spring Boot ::        (v2.3.4.RELEASE)

2020-10-16 12:22:45.463  INFO 4248 --- [           main] c.w.e.s.v.factory.VehicleFactoryMain     : Starting VehicleFactoryMain v1.0-SNAPSHOT on Miroslavs-MBP.fritz.box w
ith PID 4248
2020-10-16 12:22:45.466  INFO 4248 --- [           main] c.w.e.s.v.factory.VehicleFactoryMain     : No active profile set, falling back to default profiles: default
2020-10-16 12:22:46.216  INFO 4248 --- [           main] .s.d.r.c.RepositoryConfigurationDelegate : Bootstrapping Spring Data JPA repositories in DEFAULT mode.
2020-10-16 12:22:46.293  INFO 4248 --- [           main] .s.d.r.c.RepositoryConfigurationDelegate : Finished Spring Data repository scanning in 61ms. Found 1 JPA reposito
ry interfaces.

The application has successfully started. The application contains a tasks scheduler. Its goal is to create a dynamic interaction with the JVM in way of emitting events. The example periodical tasks do only a comparison of a different data collections. The running application emits continually JVM events that can be recorded:

Command-line recordings:

The JCMD diagnostic command line tool provides several options how to interact with the running Java application:


For the starting a flight recordings the options JFR.start with duration is used. Before is possible to start,  it is required to obtain a PID (process id):

# obtain a java process id (PID)
4248 ./vehicle-factory-main-1.0-SNAPSHOT.jar
# start readings
# $jcmd <PID> JFR.start duration=<DURATION> filename=<DESTINATION>/<FILE_NAME>
$jcmd 4248 JFR.start duration=60s filename=$JFR_READINGS/20201016_wits_spring_vehicles_factory.jfr
Started recording 1. The result will be written to:

 #check the recording status
$jcmd 4248 JFR.check                                                                              
Recording 2: name=2 duration=1m (running) 

After specified duration the recording has been finished and data are flushed to the hard drive to the specified file. Such *.JFR format file can be open inside the JDK Mission Control application.

Creating recording by UI

The recording can be directly created through UI by attaching to the already running JVM process:

JDK Flight Recording

After a specified duration the recording is automatically open inside the UI and we can start analysis. It’s quite worthy to mention that Flight Recorder already provides on the main page some useful hints related to possible application issues.

JFR: Useful hints
Sample application fixing

Now we can examine our sample application a bit more in to a details. Let’s check the  allocated Memory tab. We can observe that quite an amount of a memory is required to process the collection comparisons (in very short time couple of MBs).

JFR: Memory tab

The UI provides us quite detailed information that lead us to the problematic method. In our case:

public class ValuesProvider {
public boolean containsAllNumbers(Collection<Integer> collection) {

Let’s do a small change,  create a new recording and verify:

JFR: resolved issue

The newly created recording does not display any initial waring about primitive types conversion and Memory allocation tab looks also better. The application fix has been successful and the application does not allocated too much memory in order to compare the collections.


In the tutorial we examined a usage of the JDK Mission Control/Flight Recorded. The tutorial described how to run it and different ways to create a recordings. We have showed how JDK Mission Control uses a provided events to present consolidated views tailored to diagnose JVM runtime. The tutorial also showed on the example application how to discover and eliminate a potential issue in very short time.

Download JDK Mission Control/Fight Recorder Binaries
Next: JDK Mission Control/Flight Recorder - 8.1.0 release
Main: Java tutorials