JEP 189: Shenandoah: An Ultra-Low-Pause-Time Garbage Collector

AuthorsChristine H. Flood, Roman Kennke
OwnerRoman Kennke
Created2014/01/02 20:00
Updated2017/06/07 22:38
Componenthotspot / gc
Discussionhotspot dash gc dash dev at openjdk dot java dot net


Add a new garbage collection (GC) algorithm named Shenandoah which reduces GC pause times on extremely large heaps by doing evacuation work concurrently with Java threads and making pause times independent of heap size.


This is not the one GC to rule them all. If you are running with a heap of 20GB or less or if you are running with a single core, you are probably better off with one of the current GC algorithms.

Success Metrics

This project will be a success if we can improve SPECJBB2015's critical JOPs metric over the other collectors on heaps of 100gbs.


Modern machines have more memory and more processors than ever before. Service Level Agreement (SLA) applications guarantee response times of 10-500ms. In order to meet the lower end of that goal we need garbage collection algorithms which are efficient enough to allow programs to run in the available memory, but also optimized to never interrupt the running program for more than a handful of milliseconds. Shenandoah is an open-source low-pause time collector for OpenJDK designed to move us closer to those goals.

Shenandoah trades concurrent cpu cycles and space for pause time improvements. We've added an indirection pointer to every Java object which enables the GC threads to compact the heap while the Java threads are running. Marking and compacting are performed concurrently so we only need to pause the Java threads long enough to scan the thread stacks to find and update the roots of the object graph.

The Shenandoah algorithm is described in depth in this PPPJ2016 paper.

Here is an example of our changes to C1 to support our barriers:

LIR_Opr LIRGenerator::shenandoah_read_barrier(LIR_Opr obj, CodeEmitInfo* info, bool need_null_check) {
  if (UseShenandoahGC) {

    LabelObj* done = new LabelObj();
    LIR_Opr result = new_register(T_OBJECT);
    __ move(obj, result);
    if (need_null_check) {
      __ cmp(lir_cond_equal, result, LIR_OprFact::oopConst(NULL));
      __ branch(lir_cond_equal, T_LONG, done->label());
    LIR_Address* brooks_ptr_address = generate_address(result, BrooksPointer::byte_offset(), T_ADDRESS);
    __ load(brooks_ptr_address, result, info ? new CodeEmitInfo(info) : NULL, lir_patch_none);

    __ branch_destination(done->label());
    return result;
  } else {
    return obj;

LIR_Opr LIRGenerator::shenandoah_write_barrier(LIR_Opr obj, CodeEmitInfo* info, bool need_null_check) {
  if (UseShenandoahGC) {

    LIR_Opr result = new_register(T_OBJECT);
    LIR_Opr tmp1 = new_register(T_INT);
    LIR_Opr tmp2 = new_register(T_INT);
    __ shenandoah_wb(obj, result, tmp1, tmp2, info ? new CodeEmitInfo(info) : NULL, need_null_check);
    return result;

  } else {
    return obj;

This should give a feel for what our changes look like. There is a more in depth discussion of our changes in the attached document. Shenandoah has been implemented and will be supported by Red Hat for aarch64 and for amd64.

Development Builds

The on-going development for Shenandoah is done in the OpenJDK Shenandoah project.

Quick start for building and running latest source:

$ hg clone shenandoah-jdk9
$ cd shenandoah-jdk9/
$ sh ./
$ sh ./configure 
$ make images 
$ build/$os-$bits-normal-server-release/images/jdk/bin/java -XX:+UseShenandoahGC -Xlog:gc
[...][info][gc] Using Shenandoah


Zing/Azul has a pauseless collector, however that work has not been contributed to OpenJDK.

G1 does some parallel and concurrent work, but it does not do concurrent evacuation.

CMS does concurrent marking, but it performs young generation copying at pause times, and never compacts the old generation. This results in more time spent managing free space in the old generation as well as fragmentation issues.


Red Hat has done extensive testing for our important applications. We've developed several Shenandoah specific jtreg tests. Shenandoah is shipping in Fedora starting with Fedora 24. Running standard OpenJDK testing with -XX:+UseShenandoahGC should be sufficient.

Risks and Assumptions

There are several changes to the hotsport/src/ directory which could potentially affect applications running without Shenandoah. I've attached a document which details all of the changes made outside the src/share/vm/gc/shenandoah directory.