G1 (Garbage First) is the default garbage collector in Java 9 and later, designed to provide predictable pause times with high throughput. Here's a comprehensive guide to tuning G1 GC.
1. G1 GC Overview
How G1 Works
- Divides heap into equal-sized regions (1MB-32MB)
- Uses concurrent marking to identify live objects
- Prioritizes collection of regions with most garbage ("Garbage First")
- Provides predictable pause times through pause time goals
G1 GC Phases
- Young Collection - Eden and survivor regions
- Concurrent Marking - Identifies live objects across heap
- Mixed Collection - Collects both young and old regions
- Full GC (if necessary) - Serial collection of entire heap
2. Key G1 GC Parameters
Basic Configuration Parameters
# Enable G1 GC -XX:+UseG1GC # Basic heap settings -Xms4g -Xmx4g # Initial and maximum heap size -XX:MetaspaceSize=256m # Metaspace initial size -XX:MaxMetaspaceSize=512m # Metaspace maximum size # Region size (affects granularity) -XX:G1HeapRegionSize=16m # Set region size: 1MB, 2MB, 4MB, 8MB, 16MB, 32MB
Pause Time Targets
# Maximum pause time goal (most important parameter) -XX:MaxGCPauseMillis=200 # Target max pause time in ms # Time period for pause time target -XX:GCPauseTimeInterval=3000 # Time window for pause time target in ms
Heap Region Settings
# Young generation sizing -XX:G1NewSizePercent=5 # Minimum young gen size as % of heap -XX:G1MaxNewSizePercent=60 # Maximum young gen size as % of heap # Reserved memory -XX:G1ReservePercent=10 # Reserve % of heap to avoid promotion failure
Concurrent Phase Tuning
# Concurrent marking settings -XX:InitiatingHeapOccupancyPercent=45 # Start concurrent mark when heap is X% full -XX:ConcGCThreads=4 # Number of concurrent GC threads
3. Monitoring and Analysis Tools
Enable GC Logging
# Detailed GC logging -Xlog:gc*:file=gc.log:time:filecount=5,filesize=10m # Or for older Java versions: -XX:+PrintGCDetails -XX:+PrintGCDateStamps -XX:+PrintGCTimeStamps -Xloggc:gc.log -XX:+UseGCLogFileRotation -XX:NumberOfGCLogFiles=5 -XX:GCLogFileSize=10m # Additional diagnostic info -XX:+PrintTenuringDistribution # Age distribution of objects -XX:+PrintAdaptiveSizePolicy # GC ergonomics decisions
JVM Built-in Tools
// Enable JMX monitoring -Dcom.sun.management.jmxremote -Dcom.sun.management.jmxremote.port=9010 -Dcom.sun.management.jmxremote.ssl=false -Dcom.sun.management.jmxremote.authenticate=false
Common Monitoring Commands
# Basic JVM stats jstat -gc <pid> 1s # GC capacity and usage jstat -gccapacity <pid> 1s # Detailed GC info jstat -gcutil <pid> 1s # Heap histogram jmap -histo <pid> # Heap dump jmap -dump:live,format=b,file=heap.hprof <pid>
4. Tuning Strategies by Use Case
1. Latency-Sensitive Applications
# Focus on predictable pause times -XX:+UseG1GC -Xms8g -Xmx8g -XX:MaxGCPauseMillis=100 -XX:G1HeapRegionSize=8m -XX:G1NewSizePercent=30 -XX:G1MaxNewSizePercent=40 -XX:G1ReservePercent=15 -XX:InitiatingHeapOccupancyPercent=35 -XX:ConcGCThreads=6
2. Throughput-Oriented Applications
# Focus on overall throughput -XX:+UseG1GC -Xms16g -Xmx16g -XX:MaxGCPauseMillis=300 -XX:G1HeapRegionSize=16m -XX:G1NewSizePercent=20 -XX:G1MaxNewSizePercent=50 -XX:InitiatingHeapOccupacyPercent=50 -XX:ConcGCThreads=8
3. Large Heap Applications (64GB+)
# For very large heaps -XX:+UseG1GC -Xms64g -Xmx64g -XX:MaxGCPauseMillis=500 -XX:G1HeapRegionSize=32m -XX:G1NewSizePercent=10 -XX:G1MaxNewSizePercent=30 -XX:InitiatingHeapOccupancyPercent=40 -XX:ConcGCThreads=16 -XX:G1ConcRefinementThreads=16
5. Common Problems and Solutions
Problem 1: Long Pause Times
# Symptoms: Pause times exceeding MaxGCPauseMillis # Solutions: -XX:MaxGCPauseMillis=150 # Reduce target pause time -XX:G1NewSizePercent=25 # Reduce young gen size for shorter pauses -XX:G1MaxNewSizePercent=35 -XX:G1ReservePercent=20 # Increase reserve to avoid evacuation failures -XX:ConcGCThreads=8 # More concurrent threads
Problem 2: Frequent Full GC
# Symptoms: Full GC occurring regularly # Solutions: -XX:InitiatingHeapOccupancyPercent=35 # Start marking earlier -XX:G1ReservePercent=20 # More space for copying -XX:G1HeapWastePercent=10 # Be more aggressive in mixed GC -XX:G1MixedGCLiveThresholdPercent=85 # Collect more regions in mixed GC
Problem 3: High Promotion Failure
# Symptoms: Promotion failures causing full GC # Solutions: -XX:G1ReservePercent=25 # Increase reserve memory -XX:G1NewSizePercent=15 # Reduce young gen to leave more for old -XX:G1MaxNewSizePercent=25 -XX:InitiatingHeapOccupancyPercent=30 # Start concurrent cycle earlier
Problem 4: High CPU Usage by GC
# Symptoms: GC using too much CPU # Solutions: -XX:ConcGCThreads=4 # Reduce concurrent threads -XX:ParallelGCThreads=8 # Reduce parallel threads -XX:G1RSetUpdatingPauseTimePercent=10 # Limit time spent on RSET updates
6. Advanced Tuning Parameters
Remembered Sets Tuning
# Remembered set configuration -XX:G1RSetUpdatingPauseTimePercent=10 # Max % of time for RSET updates -XX:G1ConcRefinementThreads=8 # Threads for concurrent refinement -XX:G1ConcRefinementGreenZone=32 # Green zone threshold -XX:G1ConcRefinementYellowZone=64 # Yellow zone threshold -XX:G1ConcRefinementRedZone=96 # Red zone threshold
Mixed GC Tuning
# Mixed collection settings -XX:G1MixedGCLiveThresholdPercent=75 # Only collect regions with <75% live data -XX:G1MixedGCCountTarget=8 # Spread mixed GC over 8 cycles -XX:G1OldCSetRegionThresholdPercent=10 # Max % of heap collected in mixed GC
Heap Expansion/Contraction
# Heap resizing behavior -XX:GCTimeRatio=12 # Target % of time in GC (1/(1+12)=7.6%) -XX:MinHeapFreeRatio=30 # Minimum % free after GC -XX:MaxHeapFreeRatio=70 # Maximum % free after GC
7. Real-World Tuning Examples
Example 1: E-commerce Application
# High allocation rate, mixed workload java -XX:+UseG1GC \ -Xms12g -Xmx12g \ -XX:MaxGCPauseMillis=200 \ -XX:G1HeapRegionSize=16m \ -XX:G1NewSizePercent=30 \ -XX:G1MaxNewSizePercent=45 \ -XX:G1ReservePercent=15 \ -XX:InitiatingHeapOccupancyPercent=40 \ -XX:ConcGCThreads=6 \ -XX:ParallelGCThreads=12 \ -jar ecommerce-app.jar
Example 2: Microservices with Small Heap
# Small heap, low latency requirements java -XX:+UseG1GC \ -Xms1g -Xmx2g \ -XX:MaxGCPauseMillis=100 \ -XX:G1HeapRegionSize=2m \ -XX:G1NewSizePercent=35 \ -XX:G1MaxNewSizePercent=50 \ -XX:G1ReservePercent=20 \ -XX:InitiatingHeapOccupancyPercent=35 \ -XX:ConcGCThreads=2 \ -jar microservice.jar
Example 3: Batch Processing Application
# Large heap, throughput focused java -XX:+UseG1GC \ -Xms32g -Xmx32g \ -XX:MaxGCPauseMillis=500 \ -XX:G1HeapRegionSize=32m \ -XX:G1NewSizePercent=15 \ -XX:G1MaxNewSizePercent=30 \ -XX:G1ReservePercent=10 \ -XX:InitiatingHeapOccupancyPercent=45 \ -XX:ConcGCThreads=12 \ -XX:ParallelGCThreads=16 \ -jar batch-processor.jar
8. Diagnostic Techniques
GC Log Analysis Script
#!/bin/bash
# Analyze GC logs for common issues
echo "GC Log Analysis:"
echo "================="
# Check for Full GC
echo "Full GC occurrences:"
grep -c "Full GC" gc.log
# Check pause times
echo "Average pause time:"
grep "Pause" gc.log | awk '{sum+=$5; count++} END {print sum/count " ms"}'
# Check allocation rates
echo "Allocation rate analysis:"
grep "GC pause" gc.log | tail -10
JVM Diagnostic Code
public class G1Monitoring {
public static void main(String[] args) {
// Enable GC monitoring
startGCMonitoring();
// Your application code here
runApplication();
}
private static void startGCMonitoring() {
Thread monitorThread = new Thread(() -> {
while (true) {
try {
printMemoryStats();
Thread.sleep(5000); // Print every 5 seconds
} catch (InterruptedException e) {
Thread.currentThread().interrupt();
break;
}
}
});
monitorThread.setDaemon(true);
monitorThread.start();
}
private static void printMemoryStats() {
Runtime runtime = Runtime.getRuntime();
long maxMemory = runtime.maxMemory();
long allocatedMemory = runtime.totalMemory();
long freeMemory = runtime.freeMemory();
System.out.printf("Memory: Max=%dM, Allocated=%dM, Free=%dM, Used=%dM%n",
maxMemory / (1024 * 1024),
allocatedMemory / (1024 * 1024),
freeMemory / (1024 * 1024),
(allocatedMemory - freeMemory) / (1024 * 1024));
}
}
9. G1 GC Best Practices
1. Heap Sizing
# Set initial and max heap to same value to avoid resizing -Xms4g -Xmx4g # For containerized environments, use container-aware settings -XX:+UseContainerSupport -XX:MaxRAMPercentage=75.0
2. Region Size Selection
# Choose region size based on heap size: # <4GB: 1MB, 4-8GB: 2MB, 8-16GB: 4MB, 16-32GB: 8MB, 32-64GB: 16MB, >64GB: 32MB -XX:G1HeapRegionSize=16m
3. Concurrent Phase Tuning
# Balance between marking time and mixed GC efficiency -XX:InitiatingHeapOccupancyPercent=45 -XX:G1MixedGCLiveThresholdPercent=85 -XX:G1HeapWastePercent=5
4. Thread Configuration
# Set based on available CPUs -XX:ParallelGCThreads=<number_of_cpus> -XX:ConcGCThreads=max(1, <number_of_cpus>/4)
10. Troubleshooting Common Issues
Issue: "To-space exhausted"
# Increase reserve and start marking earlier -XX:G1ReservePercent=25 -XX:InitiatingHeapOccupancyPercent=35 -XX:G1NewSizePercent=20
Issue: "Evacuation failure"
# Reduce allocation pressure and increase reserve -XX:G1ReservePercent=20 -XX:G1NewSizePercent=25 -XX:MaxGCPauseMillis=250 # Allow longer pauses if necessary
Issue: "Humongous allocations"
# Objects larger than 50% of region size are problematic -XX:G1HeapRegionSize=32m # Increase region size for large objects -XX:G1MixedGCLiveThresholdPercent=100 # Always collect humongous regions
11. Containerized Environments
Docker/Kubernetes Configuration
FROM openjdk:11-jre # Set JVM options for containers ENV JAVA_OPTS="-XX:+UseG1GC \ -XX:+UseContainerSupport \ -XX:MaxRAMPercentage=75.0 \ -XX:MaxGCPauseMillis=200 \ -XX:InitiatingHeapOccupancyPercent=45" # For Kubernetes ENV JAVA_TOOL_OPTIONS="-XX:+UseG1GC \ -XX:+UseContainerSupport \ -XX:MaxRAMPercentage=75.0"
Kubernetes Resource Limits
apiVersion: apps/v1 kind: Deployment spec: template: spec: containers: - name: myapp image: myapp:latest resources: limits: memory: "4Gi" cpu: "2" requests: memory: "2Gi" cpu: "1" env: - name: JAVA_OPTS value: "-XX:+UseG1GC -XX:+UseContainerSupport -XX:MaxRAMPercentage=75.0"
Summary
G1 GC tuning involves balancing several factors:
- Pause time goals vs throughput
- Young generation size vs old generation collection
- Concurrent phase timing vs application workload
Start with basic settings, monitor GC behavior, and adjust parameters based on your specific application requirements. Use GC logs and monitoring tools to identify bottlenecks and optimize accordingly.
Remember: The best tuning is application-specific. Test changes in staging environments and measure the impact before deploying to production.