Operations 10 min read

Mastering JVisualVM: Detect Memory Leaks and Monitor Java Applications

JVisualVM, bundled with JDK, offers a visual interface to monitor JVM threads, memory, CPU usage, and perform heap dumps, enabling developers to detect memory leaks, analyze object references, and remotely monitor applications such as Tomcat, with step-by-step installation, plugin usage, and code examples.

Java Backend Technology
Java Backend Technology
Java Backend Technology
Mastering JVisualVM: Detect Memory Leaks and Monitor Java Applications

JVisualVM Overview

VisualVM is a profiling sub‑project of NetBeans that ships with JDK 6 update 7 and later. It can monitor threads, memory usage, CPU time per method, and objects that have been garbage‑collected. The executable jvisualvm.exe resides in the JDK bin directory.

VisualVM provides a graphical UI to view detailed information about Java applications running on a JVM, both locally and remotely. It organizes data retrieved by JDK tools and allows you to capture and save JVM data for later analysis or sharing.

After launching jvisualvm.exe, you can select local or remote JVMs similar to jconsole. The main interface looks like this:

VisualVM’s functionality is extended via plugins. Some plugins focus on GC monitoring, others on memory or thread analysis.

How to install a plugin:

1. Choose Tools > Plugins from the main menu. 2. In the Available Plugins tab, check the plugin you want to install. 3. Click Install and follow the wizard.

Example screenshot from Eclipse (process ID 22296) shows the system and JVM sections, with JVM parameters and system properties available.

The most frequently used plugins are:

Monitor (CPU, memory, classes, threads charts)

Threads (similar to jconsole)

Visual GC (shows young/old generation memory changes, GC frequency, and pause times)

VisualVM can also capture heap dumps for offline analysis.

Case Study: Simulating a Memory Leak

Steps to create a leak example:

Define a static HashMap to hold objects.

Loop to create many TestMemory instances and put them into the map.

Configure JVM parameters:

-Xms512m
-Xmx512m
-XX:-UseGCOverheadLimit
-XX:MaxPermSize=50m

Run the program and start VisualVM monitoring.

Analyzing the Memory Leak with JVisualVM

Open the Visual GC tab and observe the heap usage after each printed checkpoint ("first", "second", "third", "forth"). Screenshots show that the old generation continues to be GC'd without releasing memory, indicating a leak.

Compare two heap dumps (taken after "first" and "forth"). The comparison reveals that TestMemory instances keep increasing, confirming the leak.

To see object references, right‑click the TestMemory class and choose “Show in Instances View”. The view shows the total number of instances, their structure, and that they are referenced from CyclicDependencies via the static HashMap.

Thus the leak location is identified and can be addressed.

Full Sample Code

import java.util.HashMap;
import java.util.Map;

public class CyclicDependencies {
    // Cache object
    private static final Map<String, TestMemory> map = new HashMap<>();

    public static void main(String[] args) {
        try {
            Thread.sleep(10000); // give VisualVM time to start
        } catch (InterruptedException e) {
            e.printStackTrace();
        }
        // Add objects to cache
        for (int i = 0; i < 1_000_000; i++) {
            TestMemory t = new TestMemory();
            map.put("key" + i, t);
        }
        System.out.println("first");
        // Pause for heap dump
        try { Thread.sleep(10000); } catch (InterruptedException e) { e.printStackTrace(); }
        for (int i = 0; i < 1_000_000; i++) {
            TestMemory t = new TestMemory();
            map.put("key" + i, t);
        }
        System.out.println("second");
        try { Thread.sleep(10000); } catch (InterruptedException e) { e.printStackTrace(); }
        for (int i = 0; i < 3_000_000; i++) {
            TestMemory t = new TestMemory();
            map.put("key" + i, t);
        }
        System.out.println("third");
        try { Thread.sleep(10000); } catch (InterruptedException e) { e.printStackTrace(); }
        for (int i = 0; i < 4_000_000; i++) {
            TestMemory t = new TestMemory();
            map.put("key" + i, t);
        }
        System.out.println("forth");
        try { Thread.sleep(Integer.MAX_VALUE); } catch (InterruptedException e) { e.printStackTrace(); }
        System.out.println("qqqq");
    }
}

Remote Monitoring of Tomcat with JVisualVM

Configure the remote Tomcat’s catalina.sh to expose JMX:

JAVA_OPTS="$JAVA_OPTS \
    -Djava.rmi.server.hostname=192.168.122.128 \
    -Dcom.sun.management.jmxremote.port=18999 \
    -Dcom.sun.management.jmxremote.ssl=false \
    -Dcom.sun.management.jmxremote.authenticate=false"

Then in VisualVM:

Right‑click Remote and choose Add Remote Host , entering the server IP.

Right‑click the new host, select Add JMX Connection , and provide the configured port.

Double‑click the connection to start monitoring.

References

CSDN article

CNBlogs tutorial

Original Source

Signed-in readers can open the original source through BestHub's protected redirect.

Sign in to view source
Republication Notice

This article has been distilled and summarized from source material, then republished for learning and reference. If you believe it infringes your rights, please contactadmin@besthub.devand we will review it promptly.

TomcatJVM MonitoringHeap DumpJava profilingJVisualVM
Java Backend Technology
Written by

Java Backend Technology

Focus on Java-related technologies: SSM, Spring ecosystem, microservices, MySQL, MyCat, clustering, distributed systems, middleware, Linux, networking, multithreading. Occasionally cover DevOps tools like Jenkins, Nexus, Docker, and ELK. Also share technical insights from time to time, committed to Java full-stack development!

0 followers
Reader feedback

How this landed with the community

Sign in to like

Rate this article

Was this worth your time?

Sign in to rate
Discussion

0 Comments

Thoughtful readers leave field notes, pushback, and hard-won operational detail here.