This is part 7 of a multi-part series on memory leaks in Java. If you missed any of the last posts, you can find them here:
- Part 1 – Overview of memory leaks
- Part 2 – The static modifier and anonymous inner classes
- Part 3 – String interning and string concatenation
- Part 4 – Missing equals() and hashCode() methods
- Part 5 – Using verbose GC output to identify memory leaks
- Part 6 – Tools To Identify Memory Leaks: Profilers, VisualVM and JConsole
In the last few posts, we looked at some of the potential causes of memory leaks, and how to use the verbose output from the garbage collector to help identify memory leaks.
In this post, we’ll take a quick look at the JDK Flight Recorder and JDK Mission Control tools.
JDK Flight Recorder (JFR)
JDK Flight Recorder (JFR) is a monitoring tool that we can use to collect diagnostic and profiling data from a running Java application. It collects information about the events in the JVM while the application executes. This can help us to debug performance and memory usage issues. JFR is part of the JDK distribution, and is fully integrated into the JVM.
JFR used to be a commercial product in the Oracle JDK, but has now been open sourced. If we’re using OpenJDK (any version) we can use JFR free of charge to troubleshoot our Java apps.
We can use JFR in production since its performance overhead is negligible. The overhead is usually below 1%. For short duration apps, the percentage overhead might be higher because JFR needs some time to warm up when starting.
Flight recordings are created as our application runs. They are saved as binary formatted files.
If we are still using an older Oracle JSE8 JDK, we need to unlock the commercial features first before using the Flight Recorder:
-XX:+UnlockCommercialFeatures -XX:+FlightRecorder
These flags have been deprecated in later versions of the JDK, and are no longer needed.
There are many JFR options that we can set. These include continuous or limited time recording, saving to disk, creating a file on exit, changing the log level, changing the paths and filenames, etc. The JVM flag is:
or
-XX:FlightRecorderOptions=parameter1=value1,parameter2=value2
-XX:FlightRecorderOptions:parameter1=value1,parameter2=value2
To start a JFR recording, we use the -XX:StartFlightRecording
flag followed by any extra options. Options include delay time, recording duration, file and test names, maximum disk sizes, etc.
For example, to start a 60 second recording using the profile.jfc
event settings (in the JAVA_HOME\lib\jfr
directory), we can use the following:
-XX:StartFlightRecording=duration=60s,settings=profile,filename=demo.jfr
The following uses the default event settings file, runs until the application ends and then writes out the recording file:
-XX:StartFlightRecording=name=demo,filename=demo.jfr,dumponexit=true
We can access the recorded data once the recording file has been written (either after a specific duration or when the application has ended). The JFR files have the obvious extension of .jfr
. Remember that these files are in binary format. We must first convert them to a human readable format before we can analyse them.
The OpenJDK includes the jfr
tool to extract the data from these JFR files and convert it into human readable form. The tool can filter, summarise and print flight recording data. It can also merge and split recording files.
The jfr
tool has several subcommands, including print
, summary
, assemble
, disassemble
and metadata
See https://docs.oracle.com/en/java/javase/17/docs/specs/man/jfr.html for more details.
The output from jfr
isn’t very pretty or easy to analyse. For that, we need to use Java Mission Control.
JDK Mission Control
JDK Mission Control (JMC) is a open source suite of tools for OpenJDK. It profiles production Java applications and provides runtime diagnostics. We can use it to manage, monitor, profile and troubleshoot our Java applications.
JMC is, among other things, the client tool used to look at JFR recordings. We use JMC to visualize the event data collected by JFR. We open the JFR files in JMC which then presents the data in a number of graphical screens. This helps us visualize the data in an intuitive way. We can think of JMC as a pumped-up version of JConsole on steroids.
JMC allows us to analyse aspects of our application such as code performance, hot methods, memory and CPU usage, I/O, threads and events.
JMC was included in the JDK up to Java 8, but is now a separate download. See the following links: https://github.com/openjdk/jmc and https://wiki.openjdk.org/display/jmc/Main.
When first installed, JMC consists of the JMX (Java Management Extensions) Console and the Java Flight Recorder. JMC provides plug-in support for several IDEs such as Eclipse. More plug-ins can easily be installed from within JMC.
Heap Dumps
Heap dumps provide a snapshot of heap memory of a Java application at a particular time. They provide information on how many object instances are open and how much memory they consume. Heap dumps can help with analysing how many objects are created, and if any of them are potentially causing any memory leaks.
JFR creates heap dumps along with all the other data it collects. We can also get a heap dump of a running Java application by typing Ctrl-\
(on Solaris) or Ctrl-Break
(on Windows) in the console.
Summary
Java Flight Recorder and JDK Mission Control together create a complete tool chain to continuously collect detailed runtime information. This enables us to do after-the-fact incident analysis.
-
Java Flight Recorder is a profiling and event collection framework. It allows us to collect detailed low level information about how the JVM and the application are behaving.
-
JDK Mission Control is an advanced set of tools that enables easy, visual analysis of the extensive data collected by JFR. It includes a JMX Console and a tool for heap analysis.
In the next post, we’ll leave memory leaks and profiling behind. We’ll take pot luck with whatever Java technology catches my eye.
I look forward to your comments on this series.
Stay safe and keep learning!