Operations 16 min read

Using JDK Built‑in Tools to Monitor and Diagnose Java Applications

This article demonstrates how to use the JDK's built-in command-line and graphical tools—such as jps, jinfo, jvisualvm, jstat, jstack, and jcmd—to monitor JVM performance, analyze GC behavior, inspect thread stacks, and troubleshoot memory and configuration issues in Java applications.

Code Ape Tech Column
Code Ape Tech Column
Code Ape Tech Column
Using JDK Built‑in Tools to Monitor and Diagnose Java Applications

Hello everyone, I am Chen. You may initially feel intimidated by complex troubleshooting tools, but as you gain experience with Java programs and frameworks, these tools become increasingly handy.

This article introduces how to use the JDK's built‑in tools to analyze and locate problems in Java applications.

Using JDK Built‑in Tools to View JVM Information

The JDK ships with many command‑line and GUI utilities that help you inspect JVM details. For example, on my machine the ls command lists a large number of tools provided by JDK 8.

The following diagram shows the basic purpose of each tool.

To test the tools, we first create a program that starts ten threads, each allocating roughly a 10 MB string and then sleeping for ten seconds, thereby putting pressure on the GC.

// Start 10 threads
IntStream.rangeClosed(1, 10).mapToObj(i -> new Thread(() -> {
    while (true) {
        // Each thread loops forever, sleeps 10 s, prints 10 M data
        String payload = IntStream.rangeClosed(1, 10000000)
                .mapToObj(__ -> "a")
                .collect(Collectors.joining("")) + UUID.randomUUID().toString();
        try {
            TimeUnit.SECONDS.sleep(10);
        } catch (InterruptedException e) {
            e.printStackTrace();
        }
        System.out.println(payload.length());
    }
})).forEach(Thread::start);

TimeUnit.HOURS.sleep(1);

We then modify pom.xml to set the main class for the Spring‑Boot Maven plugin:

<plugin>
    <groupId>org.springframework.boot</groupId>
    <artifactId>spring-boot-maven-plugin</artifactId>
    <configuration>
        <mainClass>org.geekbang.time.commonmistakes.troubleshootingtools.jdktool.CommonMistakesApplication</mainClass>
    </configuration>
</plugin>

We launch the program with java -jar and set both the minimum and maximum heap size to 1 GB:

java -jar common-mistakes-0.0.1-SNAPSHOT.jar -Xms1g -Xmx1g

jps

First, jps lists Java processes, which is more convenient than using ps :

➜  ~ jps
12707
22261 Launcher
23864 common-mistakes-0.0.1-SNAPSHOT.jar
15608 RemoteMavenServer36
23243 Main
23868 Jps
22893 KotlinCompileDaemon

jinfo

Next, jinfo prints the JVM's system properties and flags, revealing that the -Xms1g and -Xmx1g options were mistakenly passed as program arguments instead of JVM options, resulting in a default max heap of about 4 GB.

➜  ~ jinfo 23864
Java System Properties:
... (output omitted for brevity) ...
VM Flags:
-XX:CICompilerCount=4 -XX:ConcGCThreads=2 -XX:G1ConcRefinementThreads=8 ... -XX:+UseG1GC

VM Arguments:
java_command: common-mistakes-0.0.1-SNAPSHOT.jar -Xms1g -Xmx1g

Printing the VM and program arguments from within the code confirms the correct configuration after moving the options before -jar :

➜  target git:(master) ✗ java -Xms1g -Xmx1g -jar common-mistakes-0.0.1-SNAPSHOT.jar test
VM options
-Xms1g
-Xmx1g
Program arguments
test

jvisualvm

We then open the heavyweight GUI tool jvisualvm to verify that the JVM parameters have taken effect and to observe GC activity, heap usage (250 MB–900 MB), and the number of active threads (22). The tool also allows manual GC and heap dump operations.

jconsole

For a more compact graphical view, jconsole can display GC curves and other MBean attributes.

jstat

On headless Linux servers, the command‑line tool jstat can output periodic GC and memory statistics. Using -gcutil every five seconds for 100 iterations shows frequent Young GC and a Full GC roughly every ten seconds.

➜  ~ jstat -gcutil 23940 5000 100
 S0     S1     E      O      M    CCS   YGC   YGCT   FGC   FGCT   CGC   CGCT    GCT
 0.00 100.00 0.36  87.63  94.30 81.06  539  14.021   33   3.972  837  0.976  18.968
 ... (additional rows omitted) ...
S0 – Survivor0, S1 – Survivor1, E – Eden, O – Old generation, M – Metaspace, YGC – Young GC count, YGCT – Young GC time, FGC – Full GC count, FGCT – Full GC time.

Thread panels in jvisualvm show that most threads are sleeping for ten seconds, matching the program logic.

Clicking the "Thread Dump" button displays a snapshot of thread stacks.

jstack

The command‑line tool jstack can also capture thread dumps:

➜  ~ jstack 23940
Full thread dump Java HotSpot 64‑Bit Server VM (11.0.3+12‑LTS mixed mode):
... (output omitted) ...
"main" #1 prio=5 os_prio=31 cpu=440.66ms elapsed=574.86s ...
"Thread-1" #13 prio=5 os_prio=31 cpu=17851.77ms elapsed=574.41s ...

The dump can be analyzed with online tools such as fastthread .

jcmd

Finally, we explore the Native Memory Tracking (NMT) feature of the HotSpot VM. Enabling it with -XX:NativeMemoryTracking=detail allows jcmd to report fine‑grained memory usage.

-Xms1g -Xmx1g -XX:ThreadStackSize=256k -XX:NativeMemoryTracking=detail

Running jcmd 24404 VM.native_memory summary shows that 32 threads collectively reserve about 4 GB of stack memory, which is unexpected because the intended stack size is only 256 KB.

➜  ~ jcmd 24404 VM.native_memory summary
Native Memory Tracking:
Total: reserved=6635310KB, committed=5337110KB
- Thread (reserved=4209797KB, committed=4209797KB) (thread #32)
  (stack: reserved=4209664KB, committed=4209664KB)

The issue stems from using the suffix k (which denotes kilobytes) when the option expects a plain number; the correct value should be 256 , not 256k . After fixing the parameter and rerunning jcmd , the reported stack size matches the expectation.

Beyond NMT, jcmd offers many other commands; jcmd 24781 help lists them all.

jcmd 24781 help

In addition to the tools covered above, the JDK includes several other utilities documented in the official JDK tools guide.

Official documentation: https://docs.oracle.com/javase/8/docs/technotes/tools/

Backend‑specific technical community

We are building a high‑quality technical exchange community. Developers, recruiters, and anyone interested in sharing job referrals are welcome to join and help each other grow.

JavaJVMmonitoringperformanceJDKTroubleshootingtools
Code Ape Tech Column
Written by

Code Ape Tech Column

Former Ant Group P8 engineer, pure technologist, sharing full‑stack Java, job interview and career advice through a column. Site: java-family.cn

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.