🌐 What is Fragmentation in Java?
What causes fragmentation?
- When objects are allocated and then freed, they leave gaps in memory.
- These gaps are too small for new objects to fit, even though there’s technically free space available.
- Over time, memory becomes fragmented — lots of small unused spaces scattered across the heap, making it inefficient for larger objects to be allocated.
Example
Imagine this memory block:
| Block 1 (live) | Block 2 (free) | Block 3 (live) | Block 4 (free) | Block 5 (live) |
Now if you want to allocate a large object, there’s no single continuous space big enough. This is external fragmentation.
🔨 How older GCs handled fragmentation (pre-Java 8)
1. Compaction (Stop-the-World)
- After removing garbage, some collectors (like Serial GC) would compact the heap by moving all live objects next to each other.
- This eliminated gaps but required a stop-the-world pause — freezing the application until compaction completed.
- This worked, but wasn’t scalable for large heaps.
2. CMS GC (deprecated) — No Compaction
- CMS tried to avoid full compaction to reduce pause times.
- This led to fragmentation issues over time, especially in long-running applications.
- When fragmentation got severe, a full GC (with compaction) was forced — a big pause hit.
🚀 How Modern GCs (G1, ZGC, Shenandoah) Solve Fragmentation
1. Region-based Memory Management (G1 GC)
- Instead of a single continuous heap, G1 splits the heap into fixed-size regions.
- Each region can hold either young objects or old objects, but regions are independent.
- When a region becomes mostly garbage, the GC reclaims and compacts only that region — a small, quick operation.
✅ This local compaction avoids the need for a huge global compaction pause.
2. Relocation and Concurrent Compaction (ZGC & Shenandoah)
- These modern collectors support concurrent compaction, meaning:
- Live objects are moved while the application is still running.
- This avoids stop-the-world pauses, even for very large heaps (100+ GB).
- They also rely on regions and relocation tables to track object moves efficiently.
✅ This makes fragmentation almost a non-issue in ZGC and Shenandoah, even in massive heaps.
Summary Table
Collector | Fragmentation Handling |
---|---|
Serial GC | Full compaction (stop-the-world) |
Parallel GC | Full compaction (stop-the-world) |
CMS GC | Minimal compaction (causes fragmentation over time) |
G1 GC | Regional compaction (low pause, fragmentation-resistant) |
ZGC & Shenandoah | Concurrent, regional compaction (almost no pause, scales to huge heaps) |
📊 Key Takeaways
✅ Older GCs (Serial, Parallel, CMS) struggled with fragmentation in large or long-running apps.
✅ Modern GCs (G1, ZGC, Shenandoah) minimize fragmentation using region-based memory and incremental or concurrent compaction.
✅ As of Java 17+, G1 is the default, making fragmentation a much smaller concern for most applications.