Master GC tuning. Learn heap sizing, collector choice, and how to achieve predictable latency in production.
JOptimize Team
Garbage collection pauses kill latency SLAs. A full GC stop-the-world pause can freeze your application for 100ms-2s. Users notice every millisecond.
This guide covers GC fundamentals, tuning strategies, and production settings to achieve consistent sub-100ms latency.
Young generation GC: 10-50ms pause Old generation GC: 100ms-2s pause Full GC: 500ms-5s pause
At 10,000 requests/sec, a 500ms pause = 5,000 dropped requests.
Heap size directly impacts GC frequency and pause time.
java -Xmx1g MyApp # Too small for high-throughput
Heap fills quickly. Frequent GC collections. Constant pauses.
java -Xmx64g MyApp # Too large
Full GC pauses are catastrophic (multi-second). Takes forever to scan entire heap.
# 50-70% utilization at steady state java -Xmx8g MyApp # For 8-core server
Heap typically 4-16GB for production servers. Size based on peak live set + headroom.
Initial estimate: live_set_size × 2 With safety margin: live_set_size × 3
java -XX:+UseG1GC -XX:MaxGCPauseMillis=200 MyApp
Pros:
Cons:
java -XX:+UseZGC -Xmx16g MyApp # Java 11+
Pros:
Cons:
java -XX:+UseShenandoahGC MyApp # Java 12+
Pros:
Cons:
G1 is the default for most Java applications.
java -XX:+UseG1GC -XX:MaxGCPauseMillis=100 MyApp
G1 tries to achieve <100ms pauses. Lower = more frequent collections.
java -XX:+UseG1GC -XX:G1HeapRegionSize=16m MyApp
For 8GB heap, use 16MB regions. Default auto-calculated, manual tuning rarely needed.
java -XX:+UseG1GC -XX:ParallelGCThreads=8 MyApp
Number of threads performing GC. Default = cores/4. For latency, use cores/2.
java -Xmx8g \ -Xlog:gc*:file=gc.log:time,level,tags \ -XX:+UseG1GC \ MyApp
Logs all GC events with timestamps.
# Analyze pauses grep "Pause" gc.log | awk '{print $NF}' | sort -n | tail -10
Shows longest pauses. Should all be <200ms.
// Using Micrometer @Component public class GCMetrics { @PostConstruct public void setupMetrics(MeterRegistry registry) { // Track GC pause times new MemoryMetrics().bindTo(registry); List<GarbageCollectorMXBean> collectors = ManagementFactory.getGarbageCollectorMXBeans(); for (GarbageCollectorMXBean bean : collectors) { registry.gauge( "jvm.gc.pause_time", bean.getCollectionTime() ); } } }
java -server \ -Xmx8g \ -XX:+UseZGC \ -XX:+AlwaysPreTouch \ -XX:+TieredCompilation \ -XX:C1CompileThreshold=1500 \ -Xlog:gc*:file=gc.log:time,level,tags \ MyApp
Explanation:
-XX:+UseZGC: Sub-10ms pauses-XX:+AlwaysPreTouch: Pre-fault pages (avoid page faults during GC)-XX:+TieredCompilation: Optimize startup + steady-state-XX:C1CompileThreshold=1500: Compile after 1500 invocations (balance startup/performance)java -server \ -Xmx16g \ -XX:+UseG1GC \ -XX:MaxGCPauseMillis=100 \ -XX:+ParallelRefProcEnabled \ -Xlog:gc*:file=gc.log \ MyApp
Cause: Heap too small
# Bad java -Xmx2g MyApp # Good: Increase heap java -Xmx8g MyApp
Cause: Object leak or heap too small
// Check: Old gen should stabilize after GC // If it keeps growing, you have a leak
Cause: Long GC pauses
# Bad: G1 trying to keep up java -XX:+UseG1GC -XX:MaxGCPauseMillis=50 MyApp # Good: Use ZGC for predictable latency java -XX:+UseZGC MyApp
GC pauses destroy latency. Heap size matters: too small = frequent pauses, too large = catastrophic full GC.
Choose collector:
Monitor GC metrics in production. Alert on full GC events.
GC tuning is one part. Thread starvation, lock contention, and allocation storms also cause spikes.
JOptimize detects GC hotspots and allocation patterns:
Use code LINKEDIN40 for 40% OFF JOptimize PRO.
Tune GC. Monitor pauses. Achieve sub-100ms latency consistently.
Master Spring Boot, security, and Java performance with hands-on courses.
JOptimize finds N+1 queries, EAGER collections, and 70+ other issues in your Java codebase — in under 30 seconds.