Stop Wasting Your Heap

The Java Virtual Machine is a wonderful little piece of software. It provides the illusion of an infinite heap – as long as you stop referring to instances you no longer need, you can keep going forever. Allocate as many little temporary object as you like; you do not have to worry about running out of memory. The JVM will automatically reclaim the memory when needed.

That said, the amount of memory that you reference at any given time, sometimes referred to as the live set, is limited by whatever memory is available to the Java heap. If you get an OutOfMemoryError, you either have a memory leak, or your application is trying to keep more memory live than can fit on the heap.

For solving the memory leak case, I will soon be demoing something pretty exciting at JavaOne 2017 that we’ve been working on (stay tuned). But what if the application is simply keeping alive too much memory? How do you go about reducing the amount of live memory required to run your application?

One way is to limit your application in various ways. Only allow N number of simultaneous users, crank down various caches you may have used in your application to speed up certain operations etc. Another is to try to look at various heap usage patterns that are known to waste heap memory. You usually end up doing a little bit of everything.

There is a little known experimental plug-in for Java Mission Control called JOverflow which can be helpful for estimating how much memory is wasted due to common heap usage anti-patterns.

Installing JOverflow

JOverflow can easily be installed from within JMC like this:

  1. Start JMC
  2. Go to Help | Install New Software
  3. Check Heap Analysis/JOverflow
  4. Click Next, Next, and finally accept the license and Finish

If you are installing into Eclipse, simply use the Experimental update site (can be found from the homepage,

The Example

The example I will be using is a heap dump from an earlier version of Java Mission Control, JMC 4.1.0. In that version we sacrificed quite a lot of heap memory, for a dubious performance optimization.

The heap dump can be downloaded from here: jmc41dump.hprof

Having the example open in JOverflow will allow you to experiment with the UI, and will likely help facilitate the understanding of the rest of this blog post.

Understanding the JOverflow User Inteface

Start by opening a heap dump. If JOverflow is properly installed in JMC (or Eclipse, if running JMC in Eclipse), you should now be presented with the JOverflow user interface.

This is what it looks like on my computer, with the example heap dump (click pictures for full size):


There are four quadrants in the JOverflow user interface. Also notice the little reset button in the upper right corner (clip_image002). It will reset all the selections in the user interface.

Object Selection

The top left quadrant, Object Selection, will show you what heap usage anti-patterns the analysis has found. The first column in the Object Selection table show the kind of objects found, implicitly telling you what was analyzed for. The second how much memory they use in total. The third column, Overhead, shows how much of the memory was wasted, in percent of the total heap used.


Referrer Tree-table

The top right quadrant contains the Referrer tree-table. This tree-table will show the aggregated reference chains for whatever is selected. Note that the way to reset the selections in the Referrer tree-table is to right click in the table. This is since you can make multiple consecutive selections to arrive at the reference chain you are interested in.


Note that the calculated overhead is all zero. This is since we have not selected the result of any analysis in the Object Selection table yet.

Class Histogram

The lower left shows a class histogram for whatever is selected, allowing you to filter on class.


Note that selections can be done directly in the pie chart. If you want to reset your selection, click the button representing the selection you have made.


Again, note that the Overhead column is still zero. This is since we have not selected the result of any analysis in the Object Selection table. That said, by selecting something directly in the class histogram, without having something selected in the Object Selection table, we can see what analysis is relevant for the selected class.

Ancestor referrer

The final table, in the lower right, will show the objects grouped by the closest ancestor referrer.


It provides a pie chart to show the memory distribution, and filter box, making it easy to home in on instances of classes belonging to specific packages. Now let’s take a look at the actual example.

Reducing Memory Usage – Example

From the Object Selection table, it seems we are wasting 17% of our used heap with 710 sparse arrays. Selecting Sparse Arrays in the Object Selection table shows us a lot immediately:


Almost all of the sparse arrays are Object arrays (see class histogram) accounting for 16% of the heap. The Referrer table-tree and the Ancestor referrer table both show that the field CircularArray.m_array keep holding on 8 of these, and that these 8 instances are responsible for almost all of overhead. So, whilst there are indeed 710 sparse arrays in our system, just 8 are responsible for almost all the heap waste.

We want to know where these circular arrays are being used, so we click the top entry in the Referrer tree-table (remember to use right-click if you want to reset the selections you make here).


So, it would seem that it is our JMX console attribute subscription storage that is wasting all that memory. This was implemented differently in a later release…

Let’s look at the second offender, the Duplicate Strings. First we reset the user interface (clip_image002). Then select Duplicate Strings in the Object Selection table. We immediately recognize that this will be a tougher job, and the law of diminishing returns probably would perhaps make us stop here. That said, it would seem like Eclipse interning some preference related keys, and JMC interning some JMC related Strings would help.

For a more fun example with duplicate strings see the following file: eclipse.hprof, where various duplicate path segment strings account for a lot of the memory waste:


Note: IIRC I tried this on a more recent version of Eclipse, and it was no longer an issue.


  • JOverflow is a plug-in for Java Mission Control
  • It can be used to identify potentially bad heap usage patterns
  • Used correctly it can reduce the amount of live memory required to run your application

Flight Recorder and Mission Control Sessions at JavaOne 2017

So, I did a quick search for Java Mission Control and Java Flight Recorder related sessions, and these are the ones I found:

Session Title

Session ID


Start Time

End Time


Distributed JVM Monitoring and Profiling Made Simple CON6836 2017-10-03
8:30 9:15 Moscone West – Room 2022
The Art of Performance Tuning CON4027 2017-10-03
9:30 10:15 Moscone West – Room 2022
Distributed Application Diagnostics Made Simple in Next-Gen Oracle Cloud CON6529
12:45 13:30 Moscone West – Room 3924
From Concept to Robotic Overlord with Robo4J CON3021 2017-10-03
15:00 15:45 Moscone West – Room 2009
G1GC Concepts and Performance Tuning CON4577 2017-10-04
12:45 13:30 Moscone West – Room 2016
Java Flight Recorder in JDK 9/Java Mission Control 6 HOL3018 2017-10-04
13:30 15:30 Hilton San Francisco Union Square (Lobby Level) – Golden Gate 4/5
Deep Diagnostics: APM and Oracle Java Flight Recorder in Oracle Cloud CON6916 2017-10-04
14:45 15:30 Moscone West – Room 2005

Let me know if I missed any session!

My JavaOne Sessions 2017

Though I feel truly honored to be one of the Featured Speakers at the JavaOne 2017 home page, I wish someone could have warned me in advance. That picture…😎😱


Anyways, clicking on the link from from my little speaker square, the one saying “See all sessions from this speaker”, currently shows me as having one talk. A Hands-on-Lab. This is not correct.

Here are the sessions (at JavaOne and OOW) where I will be speaking this year:

Session Title

Session ID


Start Time

End Time


Create a Robot and Bring it to Life KID7398 2017-09-30
13:00 15:00 Hilton San Francisco Union Square – Continental Ballroom 2/3
Distributed JVM Monitoring and Profiling Made Simple CON6836 2017-10-03
8:30 9:15 Moscone West – Room 2022
Distributed Application Diagnostics Made Simple in Next-Gen Oracle Cloud CON6529
12:45 13:30 Moscone West – Room 3924
From Concept to Robotic Overlord with Robo4J CON3021 2017-10-03
15:00 15:45 Moscone West – Room 2009
Java Flight Recorder in JDK 9/Java Mission Control 6 HOL3018 2017-10-04
13:30 15:30 Hilton San Francisco Union Square (Lobby Level) – Golden Gate 4/5

Looking forward to seeing you at JavaOne/Oracle Open World! Smile

Magnetometer Calibration in Robo4J

This article will explain how to calibrate your magnetometer in Robo4J. This will be required if you want to get as precise results as possible from your magnetometer.

Earth’s magnetic field can be distorted in various ways. If there is no distortion, rotating your magnetometer 360 degrees around the  Z-axis would result in a perfect circle (in the XY plane) centered around the origo. If there is distortion, the circle could be offset or even turned into a tilted ellipse.

There are two different type of distortions commonly discussed:

    1. Hard iron
    2. Soft iron

Hard iron effects are caused by a constant additive field, for example by a magnet. As long as the magnet stays put, relative to the magnetometer, the effect will be constant. This is what we call “bias” in Robo4J.

Soft iron effects are caused by materials that can influence the magnetic field, but which do not necessarily emit a magnetic field. For example iron and nickel. These effects are more complicated and typically turn that perfect circle (from the example above) into an ellipse.

Now, since we are dealing with a 3D magnetometer here, we are really talking about trying to turn an ellipsoid at an offset to origo, into a sphere centered around origo.

So, this is how to calibrate a magnetometer in Robo4J:

    1. Gather data from your magnetometer.
    2. Calculate the bias vector and transform matrix.
    3. Use the calculated bias vector and transformation matrix when instantiating your magnetometer.

Getting Data

If you have an Adafruit 10 DOF breakout board, or an LSM303 device, you are in luck. This is the first magnetometer we support in Robo4J, but we will add more devices as we go. This blog will talk about how to do the calibration given this device.

    1. First, clone robo4j from github
    2. Next build and install robo4j:
      ./gradlew install

    3. Next source the script with the environment variables:
      source /scripts/rpi/

    4. Then run the test program, with CSV as output format, and redirect the output to a file:
      java -cp $ROBO4J_PATH com.robo4j.hw.rpi.i2c.magnetometer.MagnetometerLSM303Test 20 1 CSV > /home/pi/magnetometer.csv

It is important that you try to hit as many points as possible, so rotate that thing like there is no tomorrow. I built a simple calibration tool that can help a little bit (but only with one axis). I have been thinking about building a massive one, using three slip rings and ball bearings, but since it would have to be large enough to accept a full sized robot to be truly useful, I know building one would put an unnecessary strain on my marriage. Smile with tongue out

Calculate the Bias Vector and Transform Matrix

This sounds hard, but is rather easy, as we’ve already added a very spiffy application to Robo4J for both visualizing your magnetometer data, and for calculating the bias vector and transform matrix. It is located in the robo4j-tools repo. Simply build and run it with your file as argument.

This is what it will look like when you start it:


If you have some spurious weird values, you may want to filter out the ones that stand out the most. Simply flip the Filter panel open, and click Filter Points. By default the values within 1.0 standard deviation (range from calculated center) will be kept. You can play with the Stddev value to get the result you want.

You can also show what the result would look like if corrected with the Bias Vector and Transformation Matrix, by clicking the “Corrected” checkbox in the Data Selection pane:


The visualization keep rotating so that the points will be shown alternatively from the XY and the ZY axis.

Using the Data When Instantiating the Magnetometer

In robo4j-hw-rpi the magnetometer can be instantiated with a Tuple3f, and a Matrix3f. Simply instantiate the tuple with the values from the bias vector, and the matrix with the values from the Transform Matrix:

Tuple3f bias = new Tuple3f(-44.689f, -2.0665f, -15.240f);
Matrix3f transform = new Matrix3f(1.887f, 5.987f, -5.709f, 5.987f, 1.528f, -2.960f, -5.709f, -2.960f, 9.761f);
MagnetometerLSM303Device magnetometer = new MagnetometerLSM303Device(I2CBus.BUS_1, 0x1e, Mode.CONTINUOUS_CONVERSION, Rate.RATE_7_5, false, bias, transform);


This blog explained how to use the Robo4J MagViz tool to calibrate a magnetometer.

Radio Silence & Robo4J

So, first of all I want to apologize for the radio silence on this blog. There are two major reasons for this radio silence:

  1. My twins
  2. Me doing blogs over at Robo4J

So, I thought I’d just do a recap of my Robo4J blogs, in the order I published them (which is probably the order someone new to Robo4J may want to read them). Smile

Here is the list:

My JavaOne 2016 Sessions

This year I’ll be doing two sessions and one HoL:

Title: Java Mission Control and JFR in JDK 9: A Sneak Peek [CON1509]

In JDK 9, the JFR APIs will become supported, so you can now rely on the JFR APIs for both controlling Oracle Java Flight Recorder and introducing your own custom JFR data into the recordings. Also, with JDK 9, a new major, very different version of the Oracle Java Mission Control feature of Oracle Java SE Advanced will be released.

This session takes a sneak peek into what the new APIs for controlling the Oracle Java Flight Recorder feature will look like and provides migration guidelines from the old APIs. It also goes through some of the highlights of the completely redesigned Oracle Java Mission Control 6.0.0, such as the automatic analysis of flight recordings. A quick intro to the new bytecode instrumentation agent used internally by Oracle Java Mission Control 6 is also provided.


Title: Using Oracle Java Flight Recorder in an Autonomous Robotic Vehicle [CON1511]

This session shows how the speaker used the Oracle Java Mission Control and Oracle Java Flight Recorder features of Oracle Java SE Advanced to record large quantities of data from the sensors in a little hobby project: a small autonomous robotic vehicle running Oracle Java SE Embedded.

The session focuses on how to use Oracle Java Flight Recorder to great advantage where resources are scarce and where overhead can cause significant problems. It also discusses how to build custom integration for Oracle Java Flight Recorder, using APIs already available in Oracle’s HotSpot JDK, and how the speaker went about designing, 3-D-printing, and building the actual hardware and software.


Title: Java Mission Control 5.5 [HOL1510] (with David Buck)

This session shows how the Oracle Java Mission Control and Oracle Java Flight Recorder features of Oracle Java SE Advanced can be used to solve various commonly encountered production-time profiling and diagnostics problems. It also shows how various Oracle Java Mission Control plug-ins can be installed and put to good use to further extend the functionality of Oracle Java Mission Control.

Among other things, the session looks at
• Reducing memory pressure
• Maximizing throughput
• Reducing heap usage (heap waste analysis)


Looking forward to seeing you at JavaOne 2016! 🙂


Using the JMC Designer View

So several people have asked me about this very unsupported feature recently. First it came up in a Google groups discussion. Then it came up again when I was helping one of the Oracle Cloud teams, and used the feature myself to modify some of the tabs to show more relevant data. And now that a colleague asked if I had a blog on how to use the JMC designer, I felt that I had to write one. So, against my better judgement, I’ll go ahead and describe, in some detail, how to use this feature in JMC 5.5.

Before we start, I would just like put in the following disclaimers:

  • Plug-ins created in JMC 5.5 will not work in JMC 6.
  • There will not be a Design view in JMC 6.
  • This is not supported functionality.

Here is the mandatory standard disclaimer:

The following blog entry will describe UNSUPPORTED functionality. This means that relying on the described APIs or functionality may BREAK your code/plugin with any given update of the JDK and/or Mission Control.

As mentioned, this disclaimer is very much applicable this time, as it is absolutely certain that this will no longer work in JMC 6.

There. I think I’ve said it plenty enough to dare continuing now.

The Designer View

Maybe you have, at times, wished that there were no dials in the Overview tab (mentioned in a Google groups discussion). Or that a certain table contained the standard deviation or max value of the aggregated events for a certain attribute (happens all the time).

Well, all but the last tab group in JMC are really customized reports that show off some specific part of the recording, usually focusing on a few different event types. And most people usually want these reports to look slightly different.

Enter the Designer View. This view is really how the rest of the JMC UI was designed. All the different tabs in JMC were created by the JMC team using the Designer View. All the tabs, except for the ones in the Events tab group, are really custom reports that highlight some aspect of the recording to help solve problems.

Starting the Designer

Starting the Designer is very easy. First open a recording. Any recording will do, but depending on what you want to do, it is good if it contains events from the event type you want to design for. Open the Designer View by hitting the Window | Show View | Designer (Unsupported) menu. Did I mention that this is unsupported?

Let’s start by removing the dials in the Overview tab. Don’t worry about messing something up – you can always reset the user interface in the preferences Window | Preferences, Java Mission Control / Flight Recorder -> Reset User Interface. That said, that extreme option will reset all your modifications to factory defaults. You can also undo changes in the design mode, which is more local and usually enough.

Here we go. Once the Designer View opens, it will show you a tree of the available tabs. In our case we want to edit the Overview. Select the General / Overview Tab, and click the “stop” button to open the Overview Tab in design mode.


This will show a layout view with boxes representing the different components. Bring up the context menu for one of the dials and select the Delete menu.


Repeat this until you have deleted all the Dials, as well as the container for the dials.


Press the play button in the Designer View to take a look at what your changes look like when live.


No more dials! Let’s take another example.

Adding Table Columns

Let’s say that you want to add some statistics for Servlet invocation events. You have the WLS tabs, but you find the Servlet tab sadly lacking in the critical-pieces-of-information department.

Note: If you do not have a WLS recording, you can download and follow this tutorial to get one. To install the plug-in, simply go to Help | Install New Software… and select the WLS tab pack.


When looking at the fabled Servlet tab, we decide that it would be very nice to see the longest lasting servlet invocations, as well as the standard deviations. First step is to open the Designer View on the Servlet tab. Right click on the Servlet Invocations by URI table (the bottom area), and select properties. You should see something like this:


Select the Columns tab. What do you know; max duration is already there, but it is not visible by default.

If you find that a table is missing a column with important information, always first check to see if the information is hidden. Go to the table, use the context menu to check what is available under Visible Columns. If there are many columns, use Configure… to see them all.


Click max duration and check the Visible check box.


Next we will add a column for the standard deviation. Click the Add… button and select the duration attribute. Click OK in the Add Event Attribute dialog when done. Next edit the Name and Description to something meaningful, then select Standard Deviation as you aggregate function.


Then hit play to look at your new and now visible column. If you sort on Max Duration, it may look something along the lines of this:


So, what if you want to add your own tab group? Well, let’s use the Smurfberry Exchange example from the tutorial.

Adding Tab Groups and Designing Tabs from Scratch

It is a well known fact that the Smurfs are trading smurfberries on their Smurfberry Exchange (SMX). They have performance problems though, so they have asked us for help. As part of solving their performance issue, we’ve recorded the actual transactions taking place.

For more information on the actual events recorded, see To solve their problem, look at the jmx.jfr in the tutorial and try to figure out what is going on. The jmx_fixed.jfr contains a recording when the problem is fixed.

This blog entry is however not about helping the smurfs solve their performance problem, but rather about adding a nifty UI so that we can see graphs over the exchange price development over time.

First close any open recording. Structural changes will not be seen in the UI until you have reloaded your recording(s). Next create a group by context clicking the root in the Designer View, and selecting New | New Group.


Edit your group to your satisfaction. Note that the placement path is a lexical comparison of strings. Usually the following format is used: /#1.0. I’ll just add it last.


Next, we want to create a tab in the tab group we just created. Context click the tab group and select New | New tab to add the tab. Fill out the New Tab wizard in a similar fashion.


That is enough to get the structure in place. Now open the recording containing the events for wish you want to design. In this case the smx.jfr file. Our new tab will, not very surprisingly, be quite empty.


Let’s click the stop button and get to work. We want one of those nifty automatic range navigators on the top, and a big chart showing the price over time. First we fix the layout. Context click on the empty area, and select Assign | Container | Rows to split the area into two.


The range navigators are all usually using 100 pixels, so select the upper container and set min and max to 100 pixels.


Next context click the upper container and assign it an Autoconfiguring Range Navigator (Assign | Other | Autoconfiguring Range Navigator). The Autoconfiguring Range Navigator shows where all the events that are represented on the tab are located in time, and allows the user to shift the time for all the components of the page, i.e. zoom into various parts of the recording.


Next we add the price chart. Select the lower container and use the context menu to select Assign | Graphics | Chart. You will now see the properties dialog for the newly added chart. Fill out the base properties.

The only thing of note here is the role selection. It can be used to define a relationship between a master component and a slave component. The slave will only show whatever is selected in the master. We noted that this were never done in more than three steps, so we ended up building the editor around that simple use case. A component can be a Master, Slave or a Slave Child. This is one of the reasons we never started supporting the Designer View. It was built only to be used by JMC developers to quickly build JMC itself. It can sometimes be a bit quirky.

Note that we are not slaving this chart to selections in any master component, so let the role remain Independent.

Next we need to configure the Left Y-axis, and the data series associated with that axis. We will only have one axis. Price is numeric, so the Content Type should be Number.


Finally we add the price data series. Click the Data Series tab and the Add… button to add the price attribute. Note that you can type “SMX” in the filter box at the top, to quickly find the right event type to select attributes from.


Next we configure the rendering of the price series. Select to show the legend (mostly useful for when there are multiple series, and you want the user to be able to select which ones to render by clicking the legenes). Select Line and Fill. Don’t forget to select Line (x,y) as style, and three different colors for Line Color, Top Fill Color and Bottom Fill Color, so that you get a nice gradient. 😉


Press the play button in the Designer View to see what it all looks like, working range navigator and all.


The Smurf economy seems to be doing fairly well. Prices are indeed increasing over time. Or perhaps there is a shortage of Smurfberries. Hard to tell. When looking at the recording where the performance problem has been fixed, the prices seem to falling towards the end. Could be a symptom of the smurfs effectively getting into high frequency trading after fixing the performance bottleneck. 😉



Saving and Sharing Designs

Now that you’ve built some amazing custom visualization, perhaps even for your own custom events, you may want to share it with others. Or even use it yourself. It is very nice to have it stored if you mistakenly press the Reset User Interface button, or if you accidentally FUBAR the user interface making it absolutely necessary to press that button. Or if you want install your changes into JMCs in multiple versions of the JDK.

To export your design as a plug-in, simply right click on the root node in the Designer View and select Export UI to Plug-in.


In the export wizard that opens, select the tabs to export. Note that you can select any tabs, even default tabs that you have overridden.


Next you get to select the ID and version of your plug-in. Higher versions will override lower versions.


Click OK to select where to store it. The resulting plug-in can be shared. To use it, simply add the plug-in to the JDK_HOME\lib\missioncontrol\dropins folder.


In this blog you learnt how to wreak absolute havoc on the JMC user interface. It’s not supported, so don’t come crying if/when something breaks. 😉

I’ve added the SMX plug-in here.

I will so very much regret posting this.

Recording JMX data into JFR

I recently saw a question on Stack Overflow regarding recording JMX data into JFR. I proposed that one could use the JFR Java API to record MBean attributes, but I realized I never did a blog post on dynamic events. So this blog post will be about dynamic JFR event generation, and how to write a configurable agent which you can use to periodically record declared JMX attributes into the Flight Recorder.

If you couldn’t care less about the implementation details, you can just download the agent jar and the example configuration file at the end of this article. 😉

And here is the usual disclaimer:

The following blog entry will describe UNSUPPORTED functionality. This means that relying on the described APIs or functionality may BREAK your code/plugin with any given update of the JDK and/or Mission Control.


Dynamic JFR Events

The JFR event API can be very useful to record custom events into the Java Flight Recorder. But what do you do when you do not know beforehand what fields the event needs to contain? Or if you wish to programmatically generate event types based on some input?

Dynamic JFR events to the rescue. You will, as usual, need a Producer:

Producer p = new Producer("Dynamic Event Example", "This example will generate a dynamic event over and over", "");

Next you need to create your DynamicEventToken. This token is what you will later use to create your events.

token = p.createDynamicInstantEvent("Dynamic Event Name", "Dynamic event description", "dynamic/path", true, true,
    new DynamicValue("rndstr", "Random String", "Contains a random string", ContentType.None, String.class),
    new DynamicValue("fraction", "Random Fraction", "Contains a random fraction between 0 and 1", ContentType.Percentage, Float.TYPE),
    new DynamicValue("timestamp", "Timestamp", "Contains a timestamp", ContentType.Timestamp, Long.TYPE));

Don’t forget to register the producer! Also note that there is one DynamicValue per attribute to record. The ContentType is used to provide the data consumer (usually JMC) with a hints for helpful visualization of the data. Check out the jmxprobes.xml file for more information on the ContentTypes.

Here is the full source for an example recording dynamic events of the same event type, but different payloads, over and over again:

package se.hirt.jmx2jfr;

import java.util.Random;


public class DynamicExample implements Runnable {
	private static final Random RND = new Random();
	private final DynamicEventToken token;

	public DynamicExample() throws Exception {
		Producer p = new Producer("Dynamic Event Example", "This example will generate a dynamic event over and over", "");
		token = p.createDynamicInstantEvent("Dynamic Event Name", "Dynamic event description", "dynamic/path", /* record thread */ true, /* record stack trace */true,
				new DynamicValue("rndstr", "Random String", "Contains a random string", ContentType.None, String.class), 
				new DynamicValue("fraction", "Random Fraction", "Contains a random fraction between 0 and 1", ContentType.Percentage, Float.TYPE),
				new DynamicValue("timestamp", "Timestamp", "Contains a timestamp", ContentType.Timestamp, Long.TYPE));

	public void run() {
		while (true) {
			InstantEvent e = token.newInstantEvent();
			e.setValue("rndstr", randomString());
			e.setValue("fraction", RND.nextDouble());
			e.setValue("timestamp", System.currentTimeMillis());
	public final static void main(String[] args) throws Exception {		
		Thread t = new Thread(new DynamicExample(), "Event generation thread");
		System.out.println("Press enter to exit!");;
	private static String randomString() {
		StringBuilder builder = new StringBuilder();
		for (int i = 0; i < RND.nextInt(10) + 1; i++) {
			builder.append(Character.toString((char) (RND.nextInt(26) + 64)));
		return builder.toString();
	private void sleep(long millis) {
		try {
		} catch (InterruptedException e) {

To run the example, especially if on a JDK prior to 8u40, remember to start with:

-XX:+UnlockCommercialFeatures –XX:+FlightRecorder

To make a recording, start JMC and hook up to the running process. Don’t forget to enable the events!


If you do a 10 second recording, you should have recorded about 10 events. Notice that properly setting the content type allows JMC to present the information in a better way. See, for example, the timestamp field:




Using the Agent

The agent allows you to configure and record JMX data into JFR without having to change any code. There is a small test snippet that you can run in the agent jar to try it out (download the agent and the settings file from the end of this article):

java -XX:+UnlockCommercialFeatures -XX:+FlightRecorder -javaagent:jmx2jfr.jar=jmxprobes.xml -cp jmx2jfr.jar se.hirt.jmx2jfr.test.HelloWorldTest

Next hook up to the HelloWorldTest process from JMC and create a 10s recording. Don’t forget to enable the MBean events:


When the recording finishes, go to the Events | Log tab. Select to only see the MBean events in the Event Types view, and select an event. You will see that MBean data has been recorded from the platform MBean server.


Use the configurations file to configure what MBeans and attributes to record, and what content types to use for the different attributes. There will be one Event Type per MBean, filled with whatever attributes you have selected:

        <!-- Time to wait before retrying getting an MBean attribute in ms -->
	<!-- Time to wait until starting in ms --> 
	<!-- How often to get the attributes and emit events for them, in ms -->
	<!-- clean: Use name or type keys for event name. Leads to cleaner event 
	     type names, but can result in name collisions if you have MBeans with 
	     the same name in the same domain.
	     canonical: ugly event type names, but guaranteed not to collide -->
	<!-- objectname:    MBean name - look it up in JMC
	     attributename: Attribute name - look it up in JMC
	     contenttype:   [None | Bytes | Timestamp | Millis | Nanos | Ticks | Address] -->

This should be fairly self explanatory. Edit the file to get the MBean attributes that you are interested in.


TL;DR – agent to easily record data from the platform MBean server into the Flight Recorder. Just edit the xml settings file, add the agent to the command line and point it to your edited settings file.



So, this is quite old news. Well, 8 weeks to be precise. Not to mention that it really has nothing to do with Java or programming. That said, I felt I should put something here on the blog. The 12th of December Malin (my wife) gave birth to two healthy babies: Sebastian and Julia.

Sebastial left, Julia (yawning) right. Both a few days old. Julia left, Sebastian right. Both a few days old.

The past few weeks have been difficult but rewarding. Very few things beat having two infants snoozing on your chest. That said, last week was hell, with the entire family sick. Now everyone is more or less well, but Julia is still fighting her cold. Since human infants are obligate nasal breathers, she gets  terrified once in a while when she can’t breathe through her nose.

Both Malin and I are a bit sleep deprived at this point. Can’t wait for them to sleep for larger continuous periods of time. Just a few months to go *fingers crossed*… Zzzzzzz…