🏆 Result: ZGC achieves 25-40x better pause times under high memory pressure
This project provides a comprehensive Docker-based benchmarking suite comparing ZGC and Shenandoah GC performance under various memory pressure scenarios. Using realistic workload simulation and isolated container environments, we demonstrate ZGC's superior low-latency performance.
| Scenario | ZGC Mean Pause | Shenandoah Mean Pause | ZGC Advantage |
|---|---|---|---|
| HIGH1 (6GB heap) | 0.12ms | 2.89ms | 24x faster |
| HIGH2 (4GB heap) | 0.07ms | 2.64ms | 38x faster |
| HIGH3 (2GB heap) | 0.11ms | 4.23ms | 38x faster |
- P95 pause times: ZGC consistently under 0.5ms, Shenandoah 9-12ms
- Maximum pause: ZGC peaks at 15ms, Shenandoah reaches 596ms
- Reliability: Both GCs successfully completed all extreme scenarios
- Docker Desktop (4GB+ memory allocation recommended)
- Internet access for base image downloads
- Python 3.9+ for log analysis and visualization
- 30 minutes for complete benchmark suite
# Clone and build
git clone https://github.com/your-repo/java-gc-bench-docker
cd java-gc-bench-docker
mvn clean package
# Run baseline comparison
docker-compose up --abort-on-container-exit
# View results
python quick_analysis.py# Run all high-memory pressure scenarios
./run-high-memory-benchmark.ps1 # Windows PowerShell
./run-high-memory-benchmark.sh # Linux/Mac
# Comprehensive analysis
python scripts/analyze_high_memory_scenarios.py- Heap: 8GB (-Xms8g -Xmx8g)
- Allocation: 65KB blocks
- Batch: 4,000 allocations per burst
- Leak Rate: Keep every 200th allocation
- Duration: 120 seconds
| Scenario | Heap | Allocation Size | Batch Size | Leak Rate | Pressure Level |
|---|---|---|---|---|---|
| HIGH1 | 6GB | 65KB | 8,000 | 1/100 | Elevated (50%) |
| HIGH2 | 4GB | 131KB | 15,000 | 1/50 | Extreme (80%) |
| HIGH3 | 2GB | 256KB | 30,000 | 1/25 | Maximum (95%) |
┌─────────────────────────────────────────┐
│ Docker Host │
├─────────────────┬─────────────────────┤
│ ZGC Container │ Shenandoah Container │
│ │ │
│ Eclipse Temurin │ Red Hat OpenJDK 21 │
│ 21-JDK │ │
│ -XX:+UseZGC │ -XX:+UseShenandoahGC│
│ │ │
│ LeakAndChurn ←──┼──→ LeakAndChurn │
│ Workload │ Workload │
└─────────────────┴─────────────────────┘
↓ ↓
┌─────────────────────────────────────────┐
│ Shared Volume: ./logs/ │
│ gc-zgc.log gc-shenandoah.log │
└─────────────────────────────────────────┘
↓
┌─────────────────────────────────────────┐
│ Python Analysis Pipeline │
│ • Parse pause times │
│ • Generate statistics │
│ • Create visualizations │
│ • Determine winner │
└─────────────────────────────────────────┘
Edit environment variables in docker-compose.yml:
environment:
HEAP: "-Xms4g -Xmx4g -XX:+AlwaysPreTouch"
WORK: "alloc.bytes=32768 churn.batch=2000 leak.every=400 run.seconds=60"# ZGC optimization
-XX:+UseZGC
-XX:SoftMaxHeapSize=6g
-XX:+AlwaysPreTouch
# Shenandoah optimization
-XX:+UseShenandoahGC
-XX:ShenandoahGCHeuristics=adaptivepython quick_analysis.py
# Output: Console summary with winner determinationpython scripts/parse_gc_logs.py
# Generates:
# - reports/gc-summary.csv (detailed metrics)
# - reports/gc-pause-distribution.png
# - reports/gc-pauses-over-time.png=== GC BENCHMARK RESULTS ===
HIGH1: ZGC wins (24x better mean pause)
HIGH2: ZGC wins (38x better mean pause)
HIGH3: ZGC wins (38x better mean pause)
OVERALL WINNER: ZGC
- P95 pause times: 0.4ms vs 12ms
- Consistent performance under pressure
- 25-40x better pause times across scenarios
The LeakAndChurn class simulates realistic enterprise application memory patterns:
public class LeakAndChurn {
private static final Map<Integer, byte[]> LEAK = new HashMap<>();
// High-rate allocation bursts (simulates request processing)
byte[] allocation = new byte[allocBytes];
// Memory fragmentation (simulates object lifecycle)
if (random.nextBoolean()) continue;
// Controlled memory leaks (simulates caches, connection pools)
if (ops++ % leakEvery == 0) {
LEAK.put(ops, allocation);
}
}Memory Pressure Characteristics:
- Burst Allocation: Simulates HTTP request processing spikes
- Fragmentation: Random object dropping creates realistic fragmentation
- Memory Leaks: Gradual accumulation simulates caches and connection pools
- Sustained Pressure: Long-running tests capture steady-state behavior
OutOfMemoryError in HIGH3 scenario:
- Expected behavior under extreme pressure
- Both GCs may fail, but logs are still generated
- Reduce memory pressure in
docker-compose-high3.yml
Docker build failures:
- Run
mvn clean packagelocally first - Use optimized Dockerfiles:
docker/*/Dockerfile.optimized - Check Docker Desktop memory allocation (4GB+ recommended)
Missing log files:
- Ensure
logs/directory exists - Check container permissions for volume mounts
- Verify containers ran to completion
We welcome contributions! Areas for enhancement:
- Additional GC implementations (G1, Parallel, etc.)
- More realistic workload patterns
- Alternative analysis methodologies
- Performance regression testing
- CI/CD integration examples
MIT License - see LICENSE file for details.
java garbage-collection performance docker benchmarking zgc shenandoah microservices jvm memory-management