G1 Garbage Collector Tuning in Java

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

  1. Young Collection - Eden and survivor regions
  2. Concurrent Marking - Identifies live objects across heap
  3. Mixed Collection - Collects both young and old regions
  4. 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.

Leave a Reply

Your email address will not be published. Required fields are marked *


Macro Nepal Helper