Master JVM Performance: Essential Tools and Real-World Usage Guide
This article explains common JVM problems such as OutOfMemoryError, memory leaks, and thread deadlocks, then introduces core monitoring tools—jps, jstack, jmap/jhat, jstat, and hprof—detailing their syntax, options, and practical examples to help Java developers diagnose and tune production applications.
In real‑world enterprise Java development you often encounter issues like OutOfMemoryError, memory leaks, thread deadlocks, lock contention, high CPU usage, and more. Understanding and solving these problems is essential for advancing as a Java programmer.
1. jps (Java Virtual Machine Process Status Tool) – Basic Tool
jps displays the JVM processes running on a host. Syntax:
jps [options] [hostid]Common options:
-q Do not output class name, JAR name, or main‑method arguments<br>-m Output arguments passed to the main method<br>-l Output the full package name of the main class or JAR<br>-v Output the arguments passed to the JVMExample:
# jps -m -l<br>2458 org.artifactory.standalone.main.Main /usr/local/artifactory-2.2.5/etc/jetty.xml<br>29920 com.sun.tools.hat.Main -port 9998 /tmp/dump.dat<br>3149 org.apache.catalina.startup.Bootstrap start<br>30972 sun.tools.jps.Jps -m -l<br>8247 org.apache.catalina.startup.Bootstrap start<br>25687 com.sun.tools.hat.Main -port 9999 dump.dat<br>21711 mrf-center.jar2. jstack
jstack prints the thread stack traces of a Java process, which is invaluable for locating the code responsible for a problem.
jstack [option] pid<br>jstack [option] executable core<br>jstack [option] [server-id@]remote-hostname-or-ipKey options:
-l Long listings, prints additional lock information (useful for deadlock analysis)<br>-m Mixed mode, includes native (C/C++) stack framesExample workflow to find the most CPU‑intensive thread:
# ps -ef | grep mrf-center | grep -v grep<br>root 21711 1 1 14:47 pts/3 00:02:10 java -jar mrf-center.jarIdentify the hottest thread with
top -Hp 21711, then convert its native thread ID to hexadecimal and grep it from jstack output:
# jstack 21711 | grep 54ee<br>"PollIntervalRetrySchedulerThread" prio=10 tid=0x00007f950043e000 nid=0x54ee in Object.wait() [0x00007f94c6eda000]The stack trace shows the thread is waiting in
Object.wait(), leading to the following idle‑wait code in the application:
// Idle wait<br>getLog().info("Thread [" + getName() + "] is idle waiting...");<br>schedulerThreadState = PollTaskSchedulerThreadState.IdleWaiting;<br>long now = System.currentTimeMillis();<br>long waitTime = now + getIdleWaitTime();<br>long timeUntilContinue = waitTime - now;<br>synchronized(sigLock) {<br> try {<br> if (!halted.get()) {<br> sigLock.wait(timeUntilContinue);<br> }<br> } catch (InterruptedException ignore) {}<br>}3. jmap (Memory Map) and jhat (Java Heap Analysis Tool)
jmap exports heap memory; jhat analyzes the dump.
jmap [option] pid<br>jmap [option] executable core<br>jmap [option] [server-id@]remote-hostname-or-ipCommon usage:
# jmap -permstat 21711To view heap configuration and usage:
# jmap -heap 21711Sample output (truncated):
Heap Configuration:<br>MinHeapFreeRatio = 40<br>MaxHeapFreeRatio = 70<br>MaxHeapSize = 2067791872 (1972.0MB)<br>...<br>Heap Usage:<br>PS Young Generation<br>Eden Space: capacity = 6422528 (6.125MB), used = 5445552 (5.19MB)<br>...<br>PS Old Generation: capacity = 35258368 (33.63MB), used = 4119544 (3.93MB)Histogram of object counts:
# jmap -histo:live 21711 | more<br>num #instances #bytes class name<br>1: 38445 5597736 <constMethodKlass><br>2: 38445 5237288 <methodKlass><br>...<br>11: 14194 454208 java.lang.String<br>12: 3809 396136 java.lang.ClassDump the heap to a file for analysis with jhat:
# jmap -dump:format=b,file=/tmp/dump.dat 21711Analyze the dump:
# jhat -port 9998 /tmp/dump.datIf the dump is large, increase the JVM heap for jhat:
# jhat -J-Xmx512m -port 9998 /tmp/dump.dat4. jstat (JVM Statistics Monitoring Tool)
jstat reports memory and GC statistics.
jstat [generalOption | outputOptions vmid [interval[s|ms] [count]]]Example showing GC info every 250 ms, four times:
# jstat -gc 21711 250 4<br>S0C S1C S0U S1U EC EU OC OU PC PU YGC YGCT FGC FGCT GCT<br>192.0 192.0 64.0 0.0 6144.0 1854.9 32000.0 4111.6 55296.0 25472.7 702 0.431 3 0.218 0.649<br>...Explanation of columns (Survivor, Eden, Old, Permanent generations, GC counts and times) follows the standard JVM heap layout diagram.
5. hprof (Heap/CPU Profiling Tool)
hprof can profile CPU usage and heap allocation.
java -agentlib:hprof[=options] ToBeProfiledClass<br>java -Xrunprof[:options] ToBeProfiledClass<br>javac -J-agentlib:hprof[=options] ToBeProfiledClassKey options (excerpt):
heap=dump|sites|all heap profiling (default: all)<br>cpu=samples|times|old CPU usage (default: off)<br>monitor=y|n monitor contention (default: n)<br>format=a|b text or binary output (default: a)<br>file=<file> output file (default: java.hprof[.txt])<br>depth=<size> stack trace depth (default: 4)<br>interval=<ms> sampling interval (default: 10)Example: CPU sampling profiling every 20 ms, depth 3:
java -agentlib:hprof=cpu=samples,interval=20,depth=3 HelloExample: CPU times profiling (bytecode‑instrumented):
javac -J-agentlib:hprof=cpu=times Hello.javaExample: Heap allocation profiling (sites):
javac -J-agentlib:hprof=heap=sites Hello.javaExample: Full heap dump:
javac -J-agentlib:hprof=heap=dump Hello.javaNote: Using
-Xrunprof:heap=siteson a production server can severely impact performance and is not recommended.
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!
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.