Operations 8 min read

Introduction to JVisualVM: Profiling, Memory Leak Analysis, and Remote Tomcat Monitoring

This article introduces JVisualVM, explains its installation and plugin system, demonstrates how to create a memory‑leak test program and analyze the leak using VisualGC and heap dumps, and shows how to configure remote JMX monitoring for a Tomcat server.

Architect's Tech Stack
Architect's Tech Stack
Architect's Tech Stack
Introduction to JVisualVM: Profiling, Memory Leak Analysis, and Remote Tomcat Monitoring

JVisualVM is a profiling tool bundled with JDK 6u7 that provides visual monitoring of JVM threads, memory usage, CPU time per method, and garbage‑collection details, and it can capture and save heap snapshots for later analysis.

The main interface displays system and JVM information, and various plugins can be installed to focus on GC, memory, threads, etc. Plugins are installed via the Tools → Plugins menu.

To illustrate its use, a sample Java program creates a static HashMap that continuously stores TestMemory objects, deliberately causing a memory leak. The program sleeps at several points to give the user time to capture heap dumps.

import java.util.HashMap;
import java.util.Map;
public class CyclicDependencies {
    private static final Map map = new HashMap();
    public static void main(String args[]) {
        try { Thread.sleep(10000); } catch (InterruptedException e) { e.printStackTrace(); }
        for (int i = 0; i < 1000000; i++) { TestMemory t = new TestMemory(); map.put("key" + i, t); }
        System.out.println("first");
        try { Thread.sleep(10000); } catch (InterruptedException e) { e.printStackTrace(); }
        for (int i = 0; i < 1000000; 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 < 3000000; 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 < 4000000; 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");
    }
}

The JVM is started with the following parameters to simplify GC behavior:

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

Using JVisualVM, the Visual GC tab shows the growth of the old generation after each program phase, indicating that objects are not being reclaimed. By taking heap dumps at the "second" and "forth" points and comparing them, the increase in TestMemory instances becomes evident.

The Instance view reveals that the TestMemory objects are retained through references from the static HashMap inside CyclicDependencies , confirming the leak source.

For remote monitoring, the Tomcat catalina.sh script is modified to expose JMX on a specific IP and port:

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"

After restarting Tomcat, JVisualVM can add a remote host, create a JMX connection using the configured port, and monitor the remote JVM just like a local one.

References: CSDN blog and ITYouKnow article.

memory leakperformance analysisGCJMXJava profilingJVisualVMTomcat monitoring
Architect's Tech Stack
Written by

Architect's Tech Stack

Java backend, microservices, distributed systems, containerized programming, and more.

0 followers
Reader feedback

How this landed with the community

login 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.