Operations 16 min read

Master JDK Built‑in Tools to Diagnose Java Application Issues

This guide walks through using JDK's native command‑line and GUI utilities—such as jps, jinfo, jvisualvm, jstat, jstack, and jcmd—to monitor JVM performance, inspect GC behavior, analyze thread dumps, and troubleshoot memory configuration problems in Java programs.

Programmer DD
Programmer DD
Programmer DD
Master JDK Built‑in Tools to Diagnose Java Application Issues

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

Using JDK Tools to View JVM Status

JDK provides many command‑line and graphical tools that help view JVM information. For example, on my machine the ls command shows numerous tools bundled with JDK 8.

Next, we introduce some common monitoring tools. The following diagram shows the basic functions of each tool:

To test these tools, we write a program that starts 10 threads, each allocating a ~10 MB string and sleeping for 10 seconds, creating GC pressure.

//启动10个线程
IntStream.rangeClosed(1, 10).mapToObj(i -> new Thread(() -> {
    while (true) {
        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);

Modify pom.xml to configure spring-boot-maven-plugin with the main class:

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

Then start the process with java -jar and set JVM parameters to make both minimum and maximum heap 1 GB:

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

After these preparations we can use JDK tools to observe and analyze the test program.

jps

Use jps to list Java processes, which is more convenient than ps:

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

jinfo

Use jinfo to print various JVM parameters:

➜ ~ jinfo 23864
Java System Properties:
#Wed Jan 29 12:49:47 CST 2020
...
user.name=zhuye
path.separator=:
os.version=10.15.2
java.runtime.name=Java(TM) SE Runtime Environment
file.encoding=UTF-8
java.vm.name=Java HotSpot(TM) 64-Bit Server VM
...
VM Flags:
-XX:CICompilerCount=4 -XX:ConcGCThreads=2 -XX:G1ConcRefinementThreads=8 -XX:G1HeapRegionSize=1048576 -XX:GCDrainStackTargetSize=64 -XX:InitialHeapSize=268435456 -XX:MarkStackSize=4194304 -XX:MaxHeapSize=4294967296 -XX:MaxNewSize=2576351232 -XX:MinHeapDeltaBytes=1048576 -XX:NonNMethodCodeHeapSize=5835340 -XX:NonProfiledCodeHeapSize=122911450 -XX:ProfiledCodeHeapSize=122911450 -XX:ReservedCodeCacheSize=251658240 -XX:+SegmentedCodeCache -XX:+UseCompressedClassPointers -XX:+UseCompressedOops -XX:+UseG1GC

VM Arguments:
java_command: common-mistakes-0.0.1-SNAPSHOT.jar -Xms1g -Xmx1g
java_class_path (initial): common-mistakes-0.0.1-SNAPSHOT.jar
Launcher Type: SUN_STANDARD

The output shows that -Xms1g and -Xmx1g were treated as program arguments, so the actual maximum heap is about 4 GB.

To verify correct JVM options, print them from the program:

System.out.println("VM options");
System.out.println(ManagementFactory.getRuntimeMXBean().getInputArguments().stream().collect(Collectors.joining(System.lineSeparator())));
System.out.println("Program arguments");
System.out.println(Arrays.stream(args).collect(Collectors.joining(System.lineSeparator())));

After moving JVM options before -jar, the output confirms they are applied:

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

jvisualvm

Launch the heavyweight tool jvisualvm to observe the program; the overview panel confirms the JVM parameters are set correctly.

The monitor panel shows GC activity roughly every 10 seconds, heap usage fluctuating between 250 MB and 900 MB, and 22 active threads. Manual GC and heap dump can be performed here.

jconsole

jconsole

provides a graphical interface to monitor GC curves and MBean attributes.

jstat

On headless servers, jstat can output GC and memory metrics at a fixed interval. For example, jstat -gcutil prints summary information every 5 seconds for 100 iterations, revealing frequent Young GC and a Full GC roughly every 10 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
  ...
“S0 represents Survivor0 usage percent, 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, etc.”

jstack

Use jstack to capture a thread dump:

➜ ~ jstack 23940
2020-01-29 13:08:15
Full thread dump Java HotSpot(TM) 64-Bit Server VM (11.0.3+12-LTS mixed mode):
"main" #1 prio=5 os_prio=31 cpu=440.66ms elapsed=574.86s tid=0x00007ffdd9800000 nid=0x2803 waiting on condition [0x0000700003849000]
   java.lang.Thread.State: TIMED_WAITING (sleeping)
   at java.lang.Thread.sleep(Native Method)
   ...
"Thread-1" #13 prio=5 os_prio=31 cpu=17851.77ms elapsed=574.41s tid=0x00007ffdda029000 nid=0x9803 waiting on condition [0x000070000539d000]
   java.lang.Thread.State: TIMED_WAITING (sleeping)
   ...

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

jcmd

Finally, jcmd can display Native Memory Tracking (NMT) data. Enable NMT with -XX:NativeMemoryTracking=detail and run:

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

The summary shows a huge amount of memory reserved for thread stacks because the unit was mistakenly set to kilobytes (256k). Correcting the value to 256 and rerunning jcmd shows the expected usage.

jcmd 24404 VM.native_memory summary
...

Running jcmd 24404 VM.native_memory detail reveals 16 suspicious threads each reserving 262144 KB (256 MB) due to the incorrect setting.

After fixing the ThreadStackSize to 256, the NMT output shows the correct memory consumption.

jcmd

also provides many other commands; use jcmd <pid> help to list them.

For a complete list of JDK tools, refer to the official documentation.

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.

Java performanceJVisualVMjcmdjstatJDK toolsJVM diagnostics
Programmer DD
Written by

Programmer DD

A tinkering programmer and author of "Spring Cloud Microservices in Action"

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.