Copying and Compacting Collectors Explained

Illustration for Copying and Compacting Collectors Explained
By Last updated:

While the Mark-and-Sweep algorithm introduced automatic garbage collection in Java, it had one big problem: heap fragmentation. Over time, free memory would be scattered across the heap, slowing down allocations. To solve this, the JVM evolved with Copying and Compacting Collectors—two strategies that improve memory efficiency and reduce allocation overhead.

In this tutorial, we’ll explore how copying and compacting collectors work, why they matter in real-world applications, and how modern JVMs implement them.


Why Copying and Compacting Collectors Matter

  • Solve memory fragmentation issues.
  • Improve allocation speed by using contiguous free space.
  • Provide predictable performance compared to Mark-and-Sweep.
  • Foundation for modern collectors like G1, ZGC, and Shenandoah.

Analogy: Imagine cleaning up a messy room. Copying is like moving important items into a clean area, leaving trash behind. Compacting is like pushing all items together neatly, leaving free space at the end.


The Copying Collector

A Copying Collector divides the heap into two regions: From-space and To-space.

Process

  1. Start from GC roots and copy live objects from From-space to To-space.
  2. After copying, swap the spaces.
  3. The old From-space is now empty and can be reused.
[From-Space] → Copy live objects → [To-Space]
Swap roles → Efficient allocation in new space

Strengths

  • Eliminates fragmentation.
  • Simple allocation with bump-the-pointer strategy.
  • Fast for heaps with many short-lived objects (e.g., Young Generation).

Weaknesses

  • Requires extra memory (since heap is divided).
  • Not ideal for large heaps with long-lived objects.

Use Case: Young Generation in generational GCs like Parallel GC and G1 GC.


The Compacting Collector

A Compacting Collector rearranges live objects within the same heap space to eliminate gaps.

Process

  1. Mark live objects (like Mark-and-Sweep).
  2. Slide them to eliminate gaps, leaving free space contiguous.
  3. Update references to new object locations.
Heap before compaction: [Live][Free][Live][Free]  
Heap after compaction:  [Live][Live][Live][Free-Free-Free]

Strengths

  • Eliminates fragmentation without doubling memory.
  • Works well with long-lived objects (Old Generation).

Weaknesses

  • Requires extra computation to move and update references.
  • Pauses can be longer than Copying Collector.

Use Case: Old Generation in collectors like Serial GC, Parallel GC, and G1 GC.


Copying vs Compacting Collectors

Feature Copying Collector Compacting Collector
Memory Requirement Extra space (From/To spaces) Works in-place, no extra memory
Performance Faster allocation, short pauses Longer pauses, but efficient use
Best for Young Generation Old Generation
Fragmentation Eliminated Eliminated

Example: GC with Copying in Action

public class CopyingGCExample {
    public static void main(String[] args) {
        for (int i = 0; i < 100000; i++) {
            String s = new String("Object-" + i);
        }
        System.gc(); // Likely triggers copying collection in young gen
    }
}
  • Most short-lived objects die quickly.
  • Survivors copied to new space → faster cleanup.

JVM Tuning for Copying & Compacting Collectors

  • -XX:+UseSerialGC → Uses copying in young gen, compacting in old gen.
  • -XX:+UseParallelGC → Parallel version for throughput.
  • -XX:+UseG1GC → Uses regions with both copying and compaction.
  • -XX:+UseZGC or -XX:+UseShenandoahGC → Concurrent compaction for ultra-low latency.

Pitfalls and Troubleshooting

  • Copying collector overhead → Not suitable for large old generations.
  • Compaction pause times → Can cause noticeable latency in real-time apps.
  • Tuning required → Heap sizing (-Xms, -Xmx, -XX:NewRatio) affects GC efficiency.

Real-World Case Study

A microservices platform using Parallel GC saw unpredictable latency due to old generation fragmentation. Switching to G1 GC reduced pauses by using region-based copying and incremental compaction, ensuring predictable response times.


JVM Version Tracker

  • Java 8 → Parallel GC (default) used copying & compacting.
  • Java 9 → G1 became default with region-based compaction.
  • Java 11 → ZGC introduced (concurrent compaction).
  • Java 17 → ZGC & Shenandoah stable.
  • Java 21+ → NUMA-aware GC, Project Lilliput optimizations.

Best Practices

  • Use Copying collectors for young generation objects.
  • Use Compacting collectors for old generation objects.
  • For low-latency apps, prefer ZGC or Shenandoah.
  • Monitor GC logs and heap fragmentation.

Conclusion & Key Takeaways

  • Copying and Compacting collectors improve on Mark-and-Sweep by eliminating fragmentation.
  • Copying is fast for short-lived objects but memory-heavy.
  • Compacting is efficient for long-lived objects but has longer pauses.
  • Modern collectors combine both approaches for optimal performance.

FAQs

1. What is the JVM memory model and why does it matter?
It defines how threads interact with memory, ensuring correctness and safety.

2. How does G1 GC differ from CMS?
G1 uses regions with incremental compaction, while CMS avoided compaction but suffered from fragmentation.

3. When should I use ZGC or Shenandoah?
When ultra-low latency and predictable pauses are critical.

4. What are JVM safepoints?
Points where threads pause for GC or JIT compilation.

5. How do I solve fragmentation issues?
Use compaction-enabled collectors like G1, ZGC, or Shenandoah.

6. Why is copying efficient for young generation?
Because most young objects die quickly, so survivors are few and copying is fast.

7. What’s the main drawback of compaction?
Longer pauses due to object relocation.

8. How do GC logs show compaction?
Look for “compaction” or “relocation” phases in GC logs.

9. What’s new in Java 21 GC improvements?
NUMA-aware GC and Project Lilliput reduce overhead and pause times.

10. How do microservices GC needs differ from monoliths?
Microservices prioritize predictable low-latency GC; monoliths prioritize throughput.