A short introduction to VisualVM and the JVM

03 Nov 2010 at 00:00:00 - 2 comment(s)

While I was reading the comments in my previous post about java 1.7, I realized that there is one thing that Java as which is great: VisualVM. If you don't know it, this is a must read post. You will discover it and see how to use it. I will talk about the Garbage Collector as well, only basic things to be able to understand Visual GC.

Where to get it?

Two possibilities, you get it from the visualvm official website or you have the JDK installed in which case you already have it. It is in the bin folder of your installation, it's called jvisualvm.

VisualVM is a visual tool integrating several commandline JDK tools and lightweight profiling capabilities. Designed for both production and development time use, it further enhances the capability of monitoring and performance analysis for the Java SE platform.

How to use it?

When you start VisualVM, this is what you get:

Now if you start a java application on your machine, for example eclipse, you will see it appear under Local.

Before we continue, you'll need to add some plugins to VisualVM. To do so, click on Tools -> Plugins in the menu then go to Available Plugins and check VisualVM-MBeans and VisualGC. Finally click on the Install button and finish the installation of the plugins. You can check the plugins installed:

Now that we have our 2 most interesting plugins, double click on the application running under local (in my example, eclipse). There are multiple tabs available: Overview, Monitor, Threads, Profiler, MBeans and VisualGC. We will go over each of them excepted the Profiler but before we continue, we will see how to connect to a remote application.

Connect to your remote application from VisualVM?

I'm sorry I will pretend you are using the spring framework here. Note that there are other ways to get jmx working but I find that this is the easiest and you can set the ports of the in/out traffic in case you have to deal with a firewall. So here are the beans you need to add to get jmx running and be able to connect to it:

<bean id="jmxRegistry" class="org.springframework.remoting.rmi.RmiRegistryFactoryBean">
  <property name="port" value="18080" />
</bean>

<bean id="mbeanServer" class="org.springframework.jmx.support.MBeanServerFactoryBean">
  <property name="locateExistingServerIfPossible" value="true" />
</bean>

<bean id="serverConnector" class="org.springframework.jmx.support.ConnectorServerFactoryBean" depends-on="jmxRegistry" destroy-method="destroy">
  <property name="objectName" value="connector:name=rmi"/>
  <property name="serviceUrl" value="service:jmx:rmi://localhost:50069/jndi/rmi://localhost:18080/server"/>
  <property name="server" ref="mbeanServer"/>
</bean>

<bean id="exporter" class="org.springframework.jmx.export.MBeanExporter" lazy-init="false">
  <property name="beans">
    <map>
      <entry key="datasources:name=myapp.database" value-ref="myDataSource" />
    </map>
  </property>
  <property name="server" ref="mbeanServer" />
</bean>

As you may have noticed, I'm setting up a MBeanExporter here. I'm referencing a data source (org.apache.commons.dbcp.BasicDataSource to be exact). We are not going to look at MBeans at the moment but now it's set up and we'll see what we can get out of it later.

To connect to your remote application, you need to right click on "Remote" in the left menu of VisualVM and Add Remote Host... then you put the IP or hostname of your remote application. Finally you right click on the host you just added and click on Add JMX Connection... In the connection field you put the serviceUrl so in my case: service:jmx:rmi://host:50069/jndi/rmi://host:18080/server. That's it, to connect you simply double click on the jmx connection you just added.

VisualVM and its possibilities

We'll go over each tabs available in VisualVM by default and the ones we got since we installed the MBeans and VisualGC plugins.

Overview

Very basic, you can see the JVM arguments used to run the application as well as the System Properties, the JVM used to run the application and that's pretty much it.

Monitor

This one is very interesting, it regroups 5 graphs where you will be able to follow CPU usage, Heap and PermGen size, the Classes (number loaded and unloaded) and finally the Threads with the number of live threads, the peak, the daemons and the total number of threads that have been started since the application is running.

All of this is in real time. You'll be able to follow what the garbage collector is doing.

Threads

I mainly use this to see if threads are locked. A thread is locked when it's red. You can see below how the Timeline is in the Threads tab:

You can get thread dump by clicking on the corresponding button on top right, this will give you more or less useful information about threads and in case they are locked, find actually what is locked. You can check the Table and Details tabs in the Threads tab, it gives more detailed information on each thread.

Visual GC

If you want to tune your VM, this is going to be your best friend. You can see in real time very useful information about the behaviour of your garbage collector such as the Perm Gen size, the Old Gen, the Eden space and the survivors. That will give you the opportunity to see the difference in behaviour while tweaking the VM.

Maybe it is interesting to discuss a bit more about the Garbage Collector (GC) as not everyone knows about it.

The Gabarge Collector is the portion of the JVM responsible for freeing memory no longer utilized by application logic. The "magic" that lets programmers not have to worry about "managing memory". Garbage collection involves traversing Java heap spaces where application objects are allocated and managed by the JVM's garbage collector.

Java heap is allocated into generational spaces: the young generation, the tenured (old) generation and the permanent generation. The young generation is divided into the Eden space and 2 survivor spaces (a "from" and a "to").

When eden space is full, minor garbage collection event occurs. Live objects in eden space are copied "to" a survivor space. Additionally, objects in the "from" survivor space are copied "to" survivor space. Each object which survives a garbage collection has its age incremented. Objects exceeding a JVM define age threshold are promoted to the tenured (old) generation space.

If "to" survivor space is too small to hold surviving Eden and "from" survivor space objetcs, objects will be promoted to "tenured" space. This is a situation that can potentially lead to performance issues. Short lived objects getting promoted to old generation will require a Full GC (stop the world kind of event) or rely on a tenured spaced concurrent collector to remove them from the Java heap.

The tenured (old) generation contains objects which have survived minor collections and copied to tenured space. The objects are garbage collected by either a stop the world single threaded full garbage collection, a stop the world multi-threaded full garbage collection or a single threaded and (mostly) concurrent garbage collection.

The permanent generation contains meta-data (objects) required by the JVM to describe the objects used in the application such as class objects and interned Strings. It is populated by the JVM at runtime based on classes in use by the application.

Here are the different JVM parameters that can affect the way garbage collection occurs and the size of the different spaces:
-Xms and -Xmx = initial and max size of the java heap (young gen + tenured gen)
-Xmn = size of young gen
-XX:NewSize and -XX:MaxNewSize = initial and max size of young gen space
-XX:NewRatio = ratio of young gen space to tenured space
-XX:PermSize and -XX:MaxPermSize = initial and max size of the perm gen space

That's it for Visual GC and the JVM. There is just MBeans left now.

MBeans

So if you've set up things like I did at the beginning of this post, you should have something like the following:

In this screenshot I already opened the mbean I exported earlier. The org.apache.commons.dbcp.BasicDataSource offers plenty of possibilities as you can see. To get the graph I double clicked on the NumActive. You can export any bean you want and have access to the public methods of your Class from there which means you can change properties of your application at runtime or do whatever you like at runtime without having to restart.

Conclusion

This post intended to give you an overview of VisualVM, with some of the great possibilities it offers. My favorites being visual gc and mbeans. I took the opportunity to talk about the garbage collector while describing Visual GC as well. Hopefully some of you will find it interesting :-)

If you want to learn more about VisualVM then you can simply go check the visualvm official website. There is a VisualVM introduction screencast availalbe there as well.

2 comments

Notify me of follow up comments