Master JVM Performance: Memory Structures, Tuning Parameters, and Monitoring Tips
Explore comprehensive JVM performance optimization, covering memory architecture, key tuning flags, garbage collector selection, common OOM scenarios, and essential monitoring tools such as jstack, jstat, JConsole, and VisualVM, with practical examples and code snippets to help you diagnose and resolve memory issues.
1. Prerequisites
JVM performance tuning involves trade‑offs and balances across many aspects; it requires a holistic view and objective data rather than guesswork. Before optimizing, understand the following fundamentals:
1. JVM garbage collectors and algorithms 2. Common JVM monitoring tools and commands 3. JVM runtime data areas 4. How to read GC logs 5. Memory allocation and reclamation strategies
2. JVM Memory Structure
The diagram shows that JVM memory consists of stack memory, heap memory, and the permanent generation (or metaspace in newer JDKs).
Young generation = Eden + S0 + S1 Heap = Young generation + Old generation JDK 1.8 and earlier: JVM memory = Stack + Heap + Permanent Generation JDK 1.8 and later: Metaspace replaces Permanent Generation and resides in native memory, so JVM memory = Stack + Heap
1. Stack Memory
Stack memory is private to each thread; a new thread gets its own stack, which is reclaimed when the thread ends. It stores primitive types, object references, and method frames.
2. Heap Memory
Heap memory comprises the young and old generations. Since JDK 1.8 the permanent generation is replaced by metaspace, which uses native memory and does not count toward the heap. The heap is the largest JVM area; all threads share it, and garbage collection operates on the heap.
Eden occupies most of the space, while the two Survivor spaces are smaller, typically in an 8:1:1 ratio.
3. Permanent Generation (Metaspace)
This area stores class metadata and interface information. It is not subject to garbage collection and is released when the JVM shuts down. If metaspace usage keeps growing, check for excessive third‑party JARs, many deployed applications, or dynamically generated proxy classes.
3. Common JVM Parameters
JVM memory limits are bound by the physical memory and the operating system. On 32‑bit systems the usable memory is usually 2‑3 GB, while 64‑bit systems have no such limit.
1. Heap Size Settings
java -server -Xmx4g -Xms4g -Xmn2g -Xss128k-Xmx4g: Sets the maximum heap size to 4 GB. -Xms4g: Sets the initial heap size to 4 GB (usually equal to -Xmx to avoid re‑allocation after GC). -Xmn2g: Sets the young generation size to 2 GB. Total heap = young + old generation. -Xss128k: Sets each thread’s stack size. Smaller values allow more threads.
java -server -Xmx4g -Xms4g -Xmn2g -Xss128k -XX:NewRatio=4 -XX:SurvivorRatio=4 -XX:MaxMetaspaceSize=16m -XX:MaxTenuringThreshold=0-XX:NewRatio=4: Sets the ratio of young to old generation to 1:4. -XX:SurvivorRatio=4: Sets the Eden to Survivor ratio to 4:1 (each Survivor occupies 1/6 of the young generation). -XX:MaxMetaspaceSize=16m: Limits metaspace to 16 MB. -XX:MaxTenuringThreshold=0: Objects skip Survivor spaces and go directly to the old generation, which can improve throughput for old‑generation‑heavy workloads.
2. Garbage Collector Selection
JVM offers serial, parallel, and concurrent collectors. Serial is suitable only for small data sets; the focus here is on parallel and concurrent collectors.
2.1 Throughput‑Oriented Parallel Collector
java -server -Xmx4g -Xms4g -Xmn2g -Xss128k -XX:+UseParallelGC -XX:ParallelGCThreads=20 -XX:+UseParallelOldGC -XX:+UseAdaptiveSizePolicy-XX:+UseParallelGC: Enables the parallel collector for the young generation. -XX:ParallelGCThreads=20: Number of threads used by the parallel collector (usually match CPU cores). -XX:+UseParallelOldGC: Enables parallel collection for the old generation (supported since JDK 6). -XX:+UseAdaptiveSizePolicy: Lets the JVM automatically adjust young generation and Survivor sizes for optimal pause times.
2.2 Latency‑Oriented Concurrent Collector
java -server -Xmx4g -Xms4g -Xmn2g -Xss128k -XX:ParallelGCThreads=20 -XX:+UseConcMarkSweepGC -XX:+UseParNewGC -XX:CMSFullGCsBeforeCompaction=5 -XX:+UseCMSCompactAtFullCollection-XX:+UseConcMarkSweepGC: Uses the concurrent collector for the old generation. -XX:+UseParNewGC: Uses the parallel collector for the young generation; can be used together with CMS. -XX:CMSFullGCsBeforeCompaction=5: Triggers a full compaction after five CMS cycles to reduce fragmentation. -XX:+UseCMSCompactAtFullCollection: Enables compaction of the old generation during a full GC.
3. Other Auxiliary Configurations
GC log printing:
-XX:+PrintGC Outputs simple GC events, e.g., [GC 118250K->113543K(130112K), 0.0094143 secs] -XX:+PrintGCDetails Outputs detailed GC information, e.g., [GC [DefNew: 8614K->781K(9088K), 0.0123035 secs] ...]
Out‑of‑Memory dump generation:
-XX:+HeapDumpOnOutOfMemoryError Creates a heap dump when OOM occurs. -XX:HeapDumpPath= Specifies the directory for the dump file.
4. Memory‑Leak Diagnosis
Typical OOM categories:
Heap OOM (java.lang.OutOfMemoryError: Java heap space)
Stack depth insufficient (java.lang.StackOverflowError)
Insufficient native threads (java.lang.OutOfMemoryError: unable to create new native thread)
Metaspace OOM (java.lang.OutOfMemoryError: Metaspace)
1. Metaspace OOM
Metaspace stores class metadata. When OOM occurs, check the metaspace size via monitoring tools and verify that -XX:MaxMetaspaceSize is not set too low.
If metaspace keeps growing, investigate excessive reflective class loading or dynamic proxy generation using -XX:+TraceClassLoading -XX:+TraceClassUnloading.
2. Stack Depth Insufficient
Common causes:
Infinite recursive calls
Excessive simultaneous method executions exhausting stack
Methods declaring many local variables
Other stack‑resource‑heavy methods
Too small -Xss configuration
/**
* VM Args: -Xss128k
*/
public class JavaStackSOF {
private int stackLength = 1;
public void stackLeak() {
stackLength++;
stackLeak();
}
public static void main(String[] args) {
JavaStackSOF oom = new JavaStackSOF();
try {
oom.stackLeak();
} catch (Throwable e) {
System.out.println("stack length:" + oom.stackLength);
throw e;
}
}
} stack length:2101
Exception in thread "main" java.lang.StackOverflowError
at com.sandy.jvm.chapter02.JavaStackSOF.stackLeak(JavaStackSOF.java:13)
at com.sandy.jvm.chapter02.JavaStackSOF.stackLeak(JavaStackSOF.java:14)
...3. Insufficient Native Threads
On Linux, non‑root users are limited to 1024 threads by default. Increase the limit by editing /etc/security/limits.d/90-nproc.conf. Also, an excessively large -Xss can reduce the maximum thread count.
4. Heap OOM
Typical causes:
Heap size too small
Unexpected traffic spikes
Loading massive data sets into memory at once
Memory leaks
General remediation steps:
1. Obtain a heap dump (recommended via JVM flags or jmap -dump:format=b,file=filename.hprof pid ). 2. Analyze the dump with MAT to locate large objects, potential leaks, and memory usage patterns.
5. JVM Monitoring
Common tools: jstack, jstat, JConsole, jvisualvm. Key metrics include region sizes, full‑GC frequency and duration, young‑GC pause times, and thread counts.
1. jstack
jstack prints thread stack traces for diagnosis, often used together with top .
Using top -Hp PID reveals the threads consuming high CPU.
Run jstack PID > log.txt to capture the stack trace for further analysis.
2. jstat
jstat provides runtime statistics.
-class Class loading statistics -compiler JIT compilation statistics -gc Heap garbage‑collection statistics -gccapacity Capacity of young, old, and permanent generations -gcmetacapacity Metaspace size -gcnew Young‑generation GC stats -gcold Old‑generation GC stats -gcutil Garbage‑collection utilization -gccause GC cause information -printcompilation Methods compiled by JIT
Example:
[root@hadoop ~]# jstat -gcutil 3346
S0 S1 E O M CCS YGC YGCT FGC FGCT GCT
52.97 0.00 42.10 13.92 97.39 98.02 8 0.020 0 0.000 0.020 0.020S0: Survivor 0 usage %
S1: Survivor 1 usage %
E: Eden usage %
O: Old generation usage %
M: Metaspace usage %
CCS: Compressed class space usage %
YGC: Young‑gen GC count
YGCT: Young‑gen GC time (s)
FGC: Full‑GC count
FGCT: Full‑GC time (s)
GCT: Total GC time (s)
3. JConsole
JConsole is a JMX‑based visual monitoring tool for local or remote JVMs.
3.1 Remote Monitoring Configuration
-Dcom.sun.management.jmxremote.port=60001 Port for JMX -Dcom.sun.management.jmxremote.authenticate=false Disable authentication -Dcom.sun.management.jmxremote.ssl=false Disable SSL -Djava.rmi.server.hostname=192.168.1.2 Host IP
3.2 Client Connection
Navigate to the JDK bin directory, launch jconsole.exe, choose “Remote Process”, enter the host IP and port, and connect.
4. jvisualvm
jvisualvm connects similarly to JConsole but offers a richer UI.
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.
Tuanzi Tech Team
Tuanzi Mobility, Ticketing & Cloud Systems – we provide mature industry solutions, share high‑quality technical insights, and warmly welcome everyone to follow and share.
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.
