It has been a while since stable Java 17 was released. Besides the new syntax sexyness, many online benchmarks has been showing a great improvement on performance either on the language’s internals or in the Garbage collectors. Some online benshmarks shows a 8% out of the box improvement between JDK v11 (the last LTS) and v17.
From the GC side, all has been significally improved. A performant GC is one of the main keys for a fast java program. Shenandoah, was been gradually released along with all the language versions, and finalized with the version 17. So Why this one is different and why you should care ?
Minimum Pause time
The main problem with GCs its pauses, they need to Stop The World (STW) to traverse the root graph paths and thus detect unreacheable memory to clear it. Parallel GC does this in concurrent mode, but the first step, the mark phase is always in the STW mode. Shenandoah in java 17 does all in concurrent, and stops the world only on the start and end of each phase.
We have :
- Concurrent mark : walks over the memory and trace reacheable objects
- Concurrent clean up : frees the memory occupied by the unreachable objects
- Concurrent ref update: Updates the references of the cleared objects
Between all phases we have a “safe point” that needs to stop the VM , it is needed to see what has been changed between the last safepoint and handle the delta. Note that during the concurrent mark, the application still runs in parallel, so it can add new variables, or allocate new heap space. This should be detected by the GC and the end (the last safepoint).
Novel Thread Stack processing
The GC needs to scan in the stack of each application’s thread to look for varibles pointing to the heap, and thus do its work. But scanning each thread’s stack, and on every GC cycle, is a heavy processing that will create visible overhead. Shenandoah uses a new mecanism called stack watermark. In a very concise definition, GC threads will scan stack concurrently, but to avoid collisions, every GC thread will put a watermark that other threads could not by pass while scanning the same stack. This is a convinient way to communicate between GC’s parallel Threads, and garantee a concurrent scan on the safe part of the same stack, concurrently.
Shenandoahs uses some heuristics strategies to better look for regions of memory to evacuate first. It has 4 modes :
- Adaptive : The default one that observes and learn from the last GC cycle.
- Static : The decision is based only on the percentage of heap occupancy.
- Compact : Runs cycles continuously ASAP after the last cycle finished.
- Aggressive : Like the compact mode, but evacuates all live objects immediately. This could be very heavy on performace.
The new (now old) java release model is making this language improving in a great pace. The last LTS is Java 17 released on sept 2021. It comes with a high improvement of the language internal processing as well as Garbage collectors. If you haven’t yet update to this version you should definitely do it.
Fom my experience, upgrading a web application v11 to v17 took me one day, and divided the build time by nearly 50%. It worth the effort !