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.
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 -Xmx1gAfter 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 KotlinCompileDaemonjinfo
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_STANDARDThe 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
testjvisualvm
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
jconsoleprovides 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=detailThe 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.
jcmdalso provides many other commands; use jcmd <pid> help to list them.
For a complete list of JDK tools, refer to the official documentation.
Signed-in readers can open the original source through BestHub's protected redirect.
This article has been distilled and summarized from source material, then republished for learning and reference. If you believe it infringes your rights, please contactand we will review it promptly.
Programmer DD
A tinkering programmer and author of "Spring Cloud Microservices in Action"
How this landed with the community
Was this worth your time?
0 Comments
Thoughtful readers leave field notes, pushback, and hard-won operational detail here.
