Java Profiling with VisualVM in Docker Container
Recently I have a requirement to test a new feature that involves using a profiler to see the performance of the application, so one option was to use Java VisualVM that comes bundled in the JDK. But this application was inside a Docker container, so there is a little config involve to make this work.
What is Java VisualVM?
Java VisualVM is a tool for profiling and monitoring the JVM and comes with a GUI that helps to visualize all kind of information like GC activity, Heap size, Classes loaded and threads. Also, it allows you to take samples of CPU and Memory usage.
Overall is a good tool to profile and monitor your JVM and to check how your application is performing and to detect memory leaks or CPU intensive tasks.
Let’s dig into how to make VisualVM works for a docker container.
There are 2 ways to use VisualVM.
1 It came bundled with the JDK instalación (since 1.6). It’s located in the /bin directory of the java folder installation under the name “jvisualvm”.
To start it, just execute:
2 You can download it as a standalone app from http://visualvm.github.io/. Just install it and run it.
After start, it’ll show you a welcome screen
Configuration to connect to a docker container.
Ok, in order to connect VisualVM to a remote JVM, in this case, one that’s running inside a Docker container, you must run your application inside that container with some JVM options to enable a JMX connection.
-Dcom.sun.management.jmxremote.rmi.port=9090 -Dcom.sun.management.jmxremote=true -Dcom.sun.management.jmxremote.port=9090 -Dcom.sun.management.jmxremote.ssl=false -Dcom.sun.management.jmxremote.authenticate=false -Dcom.sun.management.jmxremote.local.only=false -Djava.rmi.server.hostname=localhost
In my specific case, I run docker toolbox and VirtualBox, so my exposed hostname to connect to Docker container is “localhost”. It most cases should be the IP from the docker machine, which normally is something like “192.168.99.100”.
You need to be sure to expose port 9090 from your docker container. For example, using docker compose to run a Tomcat instance:
tomcat: build: ./tomcat ports: - "8080:8080" - "9090:9090"
Also, check your Dockerfile to expose the port:
Or, using the docker command:
docker run -p 9090:9090
Now that we have our application configured and running inside a Docker container, we can access it with VisualVM. So the steps are as follows.
First, create a new remote host with the IP from the Docker instance, the one you configured with JVM options from before.
If you open the JMX connection you just created, it shows you a nice panel like this.
It shows you an overall view in real time of CPU usage, Heap memory, Classes loaded and Threads.
This is a more detailed information about the Threads currently en the JVM. You can filter by Live and Finished threads. It gives you a picture in real time about the state of each thread, you can see which ones are Running, Sleeping, Waiting, Parked and Monitor with its time in milliseconds.
With Sampler you can either monitor CPU or Memory and take a snapshot any time which will give you a more detailed information about the call stack of every method that’s being executed and the objects that are currently in memory.
We’ve looked a one the tools that can help us diagnose some of the most common problems that we could face when using the JVM. It gives us an overview of the behavior of the JVM and shows us a lot of helping our information. Great thing is that it came bundled with the JDK or we can be downloaded an used in a simple way.
Hope this can help you in your everyday work as was useful for me.
See you in the next post.