Visual VM

Heap Analysis using VisualVM

5 minute read

VisualVM is a tool which used to be part of Oracle’s JDK and is now a standalone tool. This tool was spawned from the Netbeans Profiler, and it has some helpful tools to inspect a heap dump.

Opening Dumps

To load the heap dump in VisualVM, you will just go to File -> Load… and specify the File Format to be Heap Dumps….

Analyzing the Heap Dump

VisualVM offers the following sections:

  • Summary
  • Objects
  • Threads
  • OQL Console
  • R Console

For the purpose of this section we are only going to utilize the OQL Console to construct queries on the heap. There are other options in VisualVM (briefly discussed here), but we feel that the other tools presented before this offer much nicer views/data.

Summary

The Summary view gives you a quick overview of the state of the heap:

This view also lets you quickly gather the dominators for the heap, similar to the Dominator Tree in Eclipse MAT.

Objects

The Objects view groups instances by class.

Within this view, you can inspect individual instances of an object and see both the fields and the incoming references to that instance:

Threads

The Threads view visualizes the state of threads.

Within this view, you can drill down into certain threads and view what was specifically referenced in a stack frame:

OQL Console

One of the attractive features for VisualVM is that its OQL Console allows you to write Javascript code to query objects, which you can then do other functions on that data.

From the OQL Console, we will issue queries and then allow you to further play around with the language.

OQL Queries

Reference: VisualVM OQL Help

Deamon Threads

Query for Thread objects which are daemons (you can get context of Threads, since they are objects in your heap too):

select t from java.lang.Thread t where t.daemon == true

Previous versions of VisualVM used to return the results as hyperlinks, which you could then click and begin diving into the instance state:

The newer versions of VisualVM will populate the results in a view similar to the Objects view:

Mapping to JSON

Query for Thread objects (similar to last query), but return multiple attributes as JSON:

select {name: t.name.toString(), thread_id: t.tid }
from java.lang.Thread t
where t.daemon == true

Applying Javascript

VisualVM offers a helper object that represents the heap, the heap object, which offers a few useful functions.

During our OQL searching, we’ll be using heap.objects to gather the set of objects we want.

We’ll start by limiting our objects to instances of cchesser.javaperf.workshop.data.ConferenceSession and assign it to a variable called sessions (which we’ll reference later).

var sessions = heap.objects('cchesser.javaperf.workshop.data.ConferenceSession');

We’re going to find ConferenceSessions that which have tags, we’ll do that by writing a Javascript function to filter results which have tags. We’ll apply this filter to our sessions.

var sessions = heap.objects('cchesser.javaperf.workshop.data.ConferenceSession');

function hasTags(conf) {
  return conf.tags.size > 0
}

filter(sessions, hasTags);

Take that previous query and further expand it to list it in JSON with the number of tags. It is often times convenient to have a reference to the object we’re interacting with, to more easily see the available fields.

var sessions = heap.objects('cchesser.javaperf.workshop.data.ConferenceSession');

function hasTags(conf) {
  return conf.tags.size > 0
}

var withTags = filter(sessions, hasTags);

function toJSON(conf) {
return { conference: conf , tagCount : conf.tags.size };
}

map(withTags, toJSON);

We can further expand this to sort the results, descending by number of tags, and list the tags in the results:

var sessions = heap.objects('cchesser.javaperf.workshop.data.ConferenceSession');

function hasTags(conf) {
  return conf.tags.size > 0
}

var withTags = filter(sessions, hasTags);

function toJSON(conf) {
  return { conference: conf , tagCount : conf.tags.size };
}

var confs = map(withTags, toJSON);

function tagSorter(lhs, rhs) {
  return rhs.tagCount - lhs.tagCount;
}

sort(confs, tagSorter);

We could also inline most of this using the inline syntax:

function hasTags(conf) {
  return conf.tags.size > 0
}

sort(map(filter(heap.objects('cchesser.javaperf.workshop.data.ConferenceSession'), hasTags), 
 '{ conference: it, tag_count: it.tags.size, tags: toArray(it.tags.elementData) }'), 'rhs.tag_count - lhs.tag_count')

Useful Plugins

OQL Syntax Support

This plugin adds some auto complete and syntax highlighting to the OQL Console

Challenge

Apply what you’ve learned about OQL in this section and write some javascript that will show the distribution of tag counts in our conference sessions (similar to what we did with calcite mat.)

Sample Solutions

JSON Output

This solution will return the result as a JSON object.

HTML Output

This solution will return the result as an HTML <ul>.

 


  Up Next

In the next section, we'll test our knwolege.

Memory Challenge