Lesson Completion
Back to course

GC Tuning and Monitoring: Optimizing Garbage Collection

Beginner
12 minutes4.6Java

1. The Hook (The "Byte-Sized" Intro)

  • In a Nutshell: GC tuning = adjust JVM flags for throughput/latency goals.
  • Key flags: -Xms (initial heap), -Xmx (max heap), -Xmn (young gen size), -XX:MaxGCPauseMillis (pause goal).
  • GC logging: -Xlog:gc (Java 9+) tracks GC events. 3 tuning goals: (1) Throughput (app time vs GC time), (2) Latency (pause times), (3) Footprint (heap size).
  • Trade-off: Can't optimize all three! Monitoring: GC logs, JVisualVM, GC Viewer.
  • Golden rule: Set -Xms = -Xmx (avoid resizing overhead)!

Think of car tuning. GC flags = tuning knobs (engine power vs fuel efficiency). Throughput = horsepower (speed). Latency = smoothness (no jerks). Footprint = fuel tank size (memory). Can't max all three—race car (power) vs hybrid (efficiency)!


2. Conceptual Clarity (The "Simple" Tier)

💡 The Analogy

  • Throughput: Delivery truck (max cargo, don't care about speed)
  • Latency: Ambulance (fast response, minimize delays)
  • Footprint: Compact car (small, efficient)

3. Technical Mastery (The "Deep Dive")

Essential JVM Flags

FlagPurposeExample
-XmsInitial heap size-Xms2g
-XmxMaximum heap size-Xmx4g
-XmnYoung gen size-Xmn1g
-XX:NewRatioOld/Young ratio-XX:NewRatio=2 (Old=2×Young)
-XX:MaxGCPauseMillisPause time goal-XX:MaxGCPauseMillis=200
-XX:GCTimeRatioThroughput goal-XX:GCTimeRatio=99 (99% app, 1% GC)

4. Interactive & Applied Code

bash
# ======================================== # BASIC TUNING # ======================================== # Set heap size (most important!) java -Xms4g -Xmx4g -jar app.jar # ✅ Best practice: Xms = Xmx (avoid resizing) # Young generation size java -Xms4g -Xmx4g -Xmn1g -jar app.jar # Rule of thumb: Young = 25-40% of heap # ======================================== # G1 GC TUNING # ======================================== # Pause time goal java -XX:+UseG1GC \ -Xms8g -Xmx8g \ -XX:MaxGCPauseMillis=200 \ -jar app.jar # G1 tries to meet 200ms pause goal # Concurrent GC threads java -XX:+UseG1GC \ -XX:ConcGCThreads=2 \ -jar app.jar # ======================================== # PARALLEL GC TUNING (Throughput) # ======================================== # Max throughput java -XX:+UseParallelGC \ -Xms4g -Xmx4g \ -XX:GCTimeRatio=99 \ -jar app.jar # 99% app time, 1% GC time # Parallel GC threads java -XX:+UseParallelGC \ -XX:ParallelGCThreads=8 \ -jar app.jar # ======================================== # ZGC TUNING (Low Latency) # ======================================== # ZGC for large heap java -XX:+UseZGC \ -Xms16g -Xmx16g \ -jar app.jar # Pauses <10ms # ======================================== # GC LOGGING (Java 9+) # ======================================== # Basic GC logging java -Xlog:gc -jar app.jar # Detailed GC logging java -Xlog:gc*:file=gc.log:time,uptime:filecount=5,filesize=100M \ -jar app.jar # ======================================== # GC LOGGING (Java 8) # ======================================== # Java 8 style java -XX:+PrintGCDetails \ -XX:+PrintGCDateStamps \ -Xloggc:gc.log \ -jar app.jar

Java code for GC monitoring:

java
import java.lang.management.*; import java.util.*; public class GCMonitoringDemo { public static void main(String[] args) throws Exception { demonstrateGCMonitoring(); demonstrateMemoryUsage(); } // Monitor GC activity static void demonstrateGCMonitoring() { List<GarbageCollectorMXBean> gcBeans = ManagementFactory.getGarbageCollectorMXBeans(); System.out.println("=== GC MONITORING ==="); for (GarbageCollectorMXBean gcBean : gcBeans) { System.out.println("\nGC: " + gcBean.getName()); System.out.println(" Collections: " + gcBean.getCollectionCount()); System.out.println(" Time: " + gcBean.getCollectionTime() + "ms"); System.out.println(" Pools: " + Arrays.toString(gcBean.getMemoryPoolNames())); } } // Monitor memory usage static void demonstrateMemoryUsage() { MemoryMXBean memoryBean = ManagementFactory.getMemoryMXBean(); System.out.println("\n=== MEMORY USAGE ==="); // Heap memory MemoryUsage heapUsage = memoryBean.getHeapMemoryUsage(); System.out.println("Heap:"); System.out.println(" Init: " + heapUsage.getInit() / 1024 / 1024 + " MB"); System.out.println(" Used: " + heapUsage.getUsed() / 1024 / 1024 + " MB"); System.out.println(" Committed: " + heapUsage.getCommitted() / 1024 / 1024 + " MB"); System.out.println(" Max: " + heapUsage.getMax() / 1024 / 1024 + " MB"); // Non-heap memory MemoryUsage nonHeapUsage = memoryBean.getNonHeapMemoryUsage(); System.out.println("\nNon-Heap (Metaspace):"); System.out.println(" Used: " + nonHeapUsage.getUsed() / 1024 / 1024 + " MB"); } }

5. The Comparison & Decision Layer

GoalOptimize ForFlags
ThroughputApp time-XX:+UseParallelGC, -XX:GCTimeRatio=99
LatencyPause time-XX:+UseG1GC, -XX:MaxGCPauseMillis=50
FootprintHeap sizeSmaller -Xmx, Serial GC

6. The "Interview Corner" (The Edge)

The "Killer" Interview Question: "Why set -Xms equal to -Xmx?" Answer: Avoid heap resizing overhead!

bash
# ❌ BAD: Heap grows dynamically java -Xms512m -Xmx4g -jar app.jar # JVM resizes heap during runtime (expensive pauses!) # ✅ GOOD: Fixed heap size java -Xms4g -Xmx4g -jar app.jar # No resizing, predictable performance

Pro-Tips:

  1. Tuning order:
text
1. Choose GC (G1 default is good) 2. Set heap size (-Xms/-Xmx) 3. Set goals (pause time or throughput) 4. Monitor and iterate 5. Don't over-tune!
  1. GC log analysis:
bash
# Parse GC logs # Look for: # - Pause times (should be < goal) # - GC frequency (too frequent = undersized heap) # - Promotion rate (young → old) # - Full GC events (should be rare)

Topics Covered

Java Fundamentals

Tags

#java#programming#beginner-friendly

Last Updated

2025-02-01