How to Capture Java Flight Recorder (JFR)

JFR recordings are valuable artifacts for diagnosing performance problems such as CPU spikes, thread contention, deadlocks, and slow I/O. They are also valuable for tuning garbage collection and understanding what a JVM was doing in the moments before an incident.

Beginning with JDK 11, JFR became open source as part of OpenJDK and is included in virtually all standard OpenJDK distributions. This means that on any reasonably modern JVM, there is no additional licence cost or separate installation required. You simply turn it on and start collecting data.

In this article, we will walk you through the practical options for capturing a JFR recording, along with a quick-reference cheat sheet you can bookmark for later. 

Two Ways to Capture JFR Data 

These are the two ways to actually generate a JFR recording, whether you plan for it at startup or trigger it against an application that is already running. 

1. JVM Startup Flags

The simplest way to capture JFR data is to enable it right when the JVM starts. This works well for development, testing, or any situation where you already know you want a recording for the full run of the application. 

If you want to start a 60-second recording right away, use this below: 

java -XX:StartFlightRecording=duration=60s,filename=recording.jfr \
-jar myapp.jar

To keep recording continuously, dump when needed: 

java -XX:StartFlightRecording=disk=true,maxage=2h,maxsize=500m,settings=default \
-jar myapp.jar

You will often use the following parameters. duration sets how long to record, and it accepts time units such as s, m, and h, not just seconds. filename is where the .jfr file gets written. maxage and maxsize control how much historical data is retained before older chunks are discarded. settings can be either default or profile, default is the lower-overhead choice suited to continuous, always-on recordings, while profile collects more detail and is better for shorter, targeted diagnostic captures. dumponexit determines whether the recording is saved automatically when the JVM shuts down. 

2. jcmd (Diagnostic Command Tool)

This is the option you will reach for most often once an application is already running in production. jcmd ships with the JDK and can attach to a compatible JVM on the same host, provided the OS user and runtime permissions allow it. Containers and hardened production environments can restrict attach operations, so this is worth checking ahead of time. 

To see what JVM processes are running:

jcmd -l

To start a 60-second recording:

jcmd <pid> JFR.start name=rec1 duration=60s filename=rec.jfr 

To dump the current recording to a file:

jcmd <pid> JFR.dump name=rec1 filename=dump.jfr 

To stop a recording: 

jcmd <pid> JFR.stop name=rec1 

To check what recordings are active: 

jcmd <pid> JFR.check 

Here’s an example: 

jcmd 37320 JFR.start name=prod duration=120s filename=/opt/tmp/prod.jfr

A continuous recording with disk=true retains a rolling window of data in JFR’s disk repository, with maxage and maxsize controlling how much of that window is kept. Use JFR.dump to write a snapshot of that window to a .jfr file whenever you need one. This is the pattern most production teams lean on, since the recording is already there the moment something goes wrong.

Best Practice: Keep a continuous, bounded recording running at all times in production using maxage or maxsize, so you never have to reproduce an issue to get the data you need.

Note: In legacy Oracle JDK releases from 7u40 through 10, JFR was a commercial feature that had to be explicitly unlocked before use. This does not apply to JDK 11 and later, where JFR is available without the commercial-feature flags. 

java -XX:+UnlockCommercialFeatures -XX:+FlightRecorder

Tools to Analyze a Recording Once You Have It

Once you have captured a .jfr file using either of the two methods above, you will need a way to inspect its contents. These tools do not capture new data themselves; they read and interpret a recording you already have.

1. yCrash JFRPlayer: If you are looking for a more comprehensive way to analyze the JFR Data that you just captured, then I would recommend the yCrash JFRPlayer, as it provides a user-friendly interface for navigating the data. It starts with an AI-generated summary that highlights the most likely performance bottlenecks, potential root causes, and recommended fixes, helping you focus on what to investigate first. From there, you can get more insights into event timelines, stack traces, flame graphs, thread activity, garbage collection, memory allocation, lock contention, I/O, and other low-level JVM events to validate the findings and perform a far deeper analysis. This combination of automated insights and raw JFR data makes it easier to move from symptom to root cause without manually correlating hundreds of recorded events.

Note: Install yCrash JFRPlayer, which is available in both cloud and on-premises versions. Use one of the options below to get started:

Cloud service: Register and upload your JFR file online.
On-Premises: Install and run yCrash JFRPlayer on your local machine or within your organization’s environment.

2. jfr Command-Line Tool: In JDK 11 and later, the jfr command lets you inspect a .jfr file directly from the terminal, without opening a GUI. This is handy for a quick look, for scripting, or when you are on a remote server with no display. 

To show recorded events as readable text:

jfr print --events jdk.GCRecordingStop recording.jfr

To get a high-level summary:

jfr summary recording.jfr

To output all events in JSON format:

jfr print --json recording.jfr

Options such as –json can vary between JDK versions; run jfr –help print to confirm what your installed version supports.

3. JDK Mission Control (JMC): JMC is a full GUI for opening and analyzing .jfr files, and remains the go-to tool for most developers who want a visual, drill-down view of CPU, memory, threads, and I/O on the same timeline. It is a standalone download and is not bundled with JDK 11 and later, so install it separately, launch it, then use File, then Open Recording to load your .jfr file.

4. Community Tools (jfr-cli): Beyond what ships with the JDK, community projects such as jfr-cli add extra filtering, reporting, and automation on top of what jfr and JMC already provide, worth knowing about if you need something more tailored to your own reporting pipeline.

Quick-Start Cheat Sheet

Here are the commands you will reach for most often. You can probably save it for later. 

What You Want To Do What Command Should You Use
Grab a 5-minute recording with detailed profiling jcmd <pid> JFR.start name=prof duration=300s settings=profile filename=/tmp/prof.jfr 
Set up a continuous recording, dump whenever you need it jcmd <pid> JFR.start name=cont settings=default disk=true maxage=2h maxsize=500m
Dump a running continuous recording once something goes wrong jcmd <pid> JFR.dump name=cont filename=/tmp/cont.jfr 
Open a recording in JMC (after installing JDK Mission Control) jmc (then File, Open Recording) 
Get a quick summary from the command line jfr summary recording.jfr 
Print specific events from the command line jfr print –events jdk.GarbageCollection recording.jfr 

There you go. I hope you found this blog useful. Remember, capturing a JFR recording is only the first step, but it is the step that determines whether you have usable evidence when something goes wrong. Whether you enable it at startup, trigger it on demand with jcmd, or keep a continuous rolling recording running in the background, the goal is the same: have the data ready before you need it, not after. Once you have gathered this data, you can use any one of the above-mentioned JFR tools to analyze it and deal with the production issue you are facing. 

3 thoughts on “How to Capture Java Flight Recorder (JFR)

Add yours

Share your Thoughts!

Up ↑

Discover more from yCrash

Subscribe now to keep reading and get access to the full archive.

Continue reading