Fundamentals 27 min read

Exploring Modern Java Garbage Collectors: G1, ZGC, and Shenandoah

This article examines the evolution of Java garbage collectors, detailing the design and operation of G1, ZGC, and Shenandoah, and explains key concepts such as generational collection, write and read barriers, SATB, RSet, and multi‑view mapping with illustrative code and diagrams.

Alibaba Cloud Developer
Alibaba Cloud Developer
Alibaba Cloud Developer
Exploring Modern Java Garbage Collectors: G1, ZGC, and Shenandoah

Garbage Collector Overview

The article builds on a previous introduction to garbage collection fundamentals and explores several cutting‑edge Java garbage collectors, focusing on G1, ZGC (also known as C4), and Shenandoah.

1. Garbage Collector Introduction

Most industrial garbage collectors combine the algorithms discussed earlier and follow a generational design. The most common and newest collectors are listed, each typically used in fixed combinations.

CMS – suitable for the old generation, deprecated in JDK 9 and removed in JDK 14.

Parallel Scavenge – incompatible with many collectors because it is not based on the HotSpot VM framework.

Parallel Scavenge + Parallel Old – adaptive strategy for throughput‑sensitive scenarios.

C4 and ZGC – different implementations of the same algorithm; ZGC currently lacks generational design.

C4, ZGC, Shenandoah – share many algorithmic ideas while each has unique design concepts.

The relationship between various collectors and their algorithms is illustrated below:

Serial: mark‑copy

Serial Old: mark‑compact

ParNew: mark‑copy

Parallel Scavenge: mark‑copy

Parallel Old: mark‑compact

CMS (Concurrent‑Mark‑Sweep): (concurrent) mark‑sweep

G1 (Garbage‑First): concurrent mark + parallel copy

ZGC/C4: concurrent mark + concurrent copy

Shenandoah GC: concurrent mark + concurrent copy

2. G1 Garbage Collector

G1 became the default collector starting with JDK 9. It partitions the heap into equal‑sized regions. Young GC uses parallel copying; Mixed GC combines selected high‑benefit old‑generation regions with all young regions. G1 can be viewed as a mark‑copy implementation.

G1’s old‑generation marking consists of four phases:

Initial Mark (STW)

Concurrent Mark

Final Mark (STW)

Cleanup (STW)

To reduce STW time, G1 uses a Remembered Set (RSet) to track inter‑generational references and SATB (Snapshot‑At‑The‑Beginning) to record reference changes during concurrent marking.

Write barriers in G1 are split into pre_write_barrier and post_write_barrier. The following code shows how a field assignment triggers these barriers:

// Assign a new value to a field
void assign_new_value(oop* field, oop value) {
  pre_write_barrier(field);   // Step 1
  *field = value;              // Step 2
  post_write_barrier(field, value); // Step 3
}

RSet records which references need to be tracked. It uses a “who‑references‑me” hash‑table approach, recording cross‑generation references that are required for efficient old‑generation collection.

3. ZGC / C4 Garbage Collector

ZGC addresses G1’s limitations (heap utilization and pause times) by adopting a fully concurrent, low‑latency design contributed by Oracle in 2017 and integrated in JDK 14 (JEP‑333). It implements a concurrent mark‑copy algorithm with two sub‑phases for copying: Relocate and Remap, keeping pause times under 10 ms.

ZGC uses SATB implemented via read barriers and a multi‑view mapping scheme. Memory is divided into pages (small 2 MB, medium 32 MB, large OS pages). Each object reference is a “color pointer” that encodes the physical address and metadata bits (Marked0, Marked1, Remapped, Finalizable).

Read barriers capture reference changes during concurrent marking, ensuring a complete snapshot. After marking, a remark phase processes the SATB queue to finalize the mark.

void pre_write_barrier(oop* field) {
  oop old_value = *field;
  if (old_value != null) {
    if ($gc_phase == GC_CONCURRENT_MARK) {
      $current_thread->satb_mark_queue->enqueue(old_value);
    }
  }
}

4. Shenandoah Garbage Collector

Shenandoah, contributed by Red Hat and open‑sourced in JDK 12 (JEP‑189), also provides concurrent marking and concurrent copying but relies on both read and write barriers plus “brook pointers” (forwarding pointers) for object movement.

The heap is split into regions (256 KB – 32 MB). During concurrent copying, write barriers trigger object evacuation, and forward pointers are updated atomically.

stub evacuate(obj) {
    if (in-collection-set(obj) && fwd-ptrs-to-self(obj)) {
        copy = copy(obj);
        CAS(fwd-ptr-addr(obj), obj, copy);
    }
}

Read barriers resolve the real address of an object when it is accessed, while write barriers ensure that updates occur in the correct region.

void updateObject(Foo foo) {
    // Read barrier
    Bar b1 = readBarrier(foo).bar;
    // Read barrier
    Baz baz = readBarrier(b1).baz;
    X value = makeSomeValue(baz);
    // Write barrier
    writeBarrier(b1).x = readBarrier(value);
}

Shenandoah is best suited for large heaps; for smaller heaps or latency‑insensitive workloads, traditional stop‑the‑world collectors may provide higher throughput.

5. Summary

The article reviewed several modern Java garbage collectors—G1, C4/ZGC, and Shenandoah—highlighting the trend toward fully concurrent algorithms that minimize pause times in large‑heap environments. While concurrent marking and copying reduce application stalls, they require sufficient heap space and careful management of reference‑tracking structures such as RSet, SATB, and multi‑view mappings.

Reference Materials [1] http://dinfuehr.github.io/blog/a-first-look-into-zgc/ [2] https://rkennke.wordpress.com/2013/06/10/shenandoah-a-pauseless-gc-for-openjdk/ [3] https://shipilev.net/talks/devoxx-Nov2017-shenandoah.pdf [4] http://go.azul.com/continuously-concurrent-compacting-collector [5] https://dl.acm.org/doi/10.1145/800055.802042 [6] http://citeseerx.ist.psu.edu/viewdoc/download?doi=10.1.1.63.6386&rep=rep1&type=pdf [7] https://www.infoq.com/articles/tuning-tips-G1-GC/ [8] https://developers.redhat.com/blog/2019/06/27/shenandoah-gc-in-jdk-13-part-1-load-reference-barriers/
Original Source

Signed-in readers can open the original source through BestHub's protected redirect.

Sign in to view source
Republication Notice

This article has been distilled and summarized from source material, then republished for learning and reference. If you believe it infringes your rights, please contactadmin@besthub.devand we will review it promptly.

javaGarbage CollectionzgcG1ShenandoahConcurrent Algorithms
Alibaba Cloud Developer
Written by

Alibaba Cloud Developer

Alibaba's official tech channel, featuring all of its technology innovations.

0 followers
Reader feedback

How this landed with the community

Sign in to like

Rate this article

Was this worth your time?

Sign in to rate
Discussion

0 Comments

Thoughtful readers leave field notes, pushback, and hard-won operational detail here.