The OpenJDK project is about to release JDK 26 in a few days. This is a good opportunity to add information about notable changes to the stop-the-world collectors in the Hotspot VM.
The complete list of resolved/closed changes for the GC subcomponent for JDK 26 is here, containing around 380 changes that were resolved or closed in total.
Close to double the amount of issues were closed in JDK 26 compared to the last release. Some brief analysis indicates that the composition of changes is different: there were many small changes both end-user visible or just code quality improvements rather than a few single, larger changes. Most larger changes were integrated early, meaning most development time was spent in earlier release periods. Additionally a few new contributors to the GC component had meaningful impact.
Let’s start with the breakdown of in my opinion changes worth mentioning categorized by stop-the-world garbage collector for JDK 26.
All Collectors
This release there have been a significant amount of changes affecting all garbage collectors (including non-stop-the-world collectors):
garbage collection CPU usage accounting improved significantly. The VM now tracks GC CPU usage in a more complete manner, including both time spent inside garbage collection pauses as well as CPU time spent in concurrent work (e.g. concurrent marking) or adjacent tasks like string deduplication.
In earlier releases the information was fragmented or required manual aggregation, and were difficult or impossible to obtain reliably for users.
Now there are multiple ways of obtaining that information - one way to do so is enabling cpu=info logging that prints something like the following at VM exit:
[info ][cpu] === CPU time Statistics =========================================<br>[info ][cpu] CPUs<br>[info ][cpu] s % utilized<br>[info ][cpu] Process<br>[info ][cpu] Total 443.4045 100.00 9.0<br>[info ][cpu] Garbage Collection 365.2198 82.37 7.4<br>[info ][cpu] GC Threads 365.1982 82.36 7.4<br>[info ][cpu] VM Thread 0.0216 0.00 0.0<br>[info ][cpu] =================================================================
The output shows Total Process and Garbage Collection CPU usage in absolute and relative terms (JDK-8359110). Hsperf counters were updated, see JDK-8315149 for the exact counter names. There is also a programmatic way of obtaining this information in your own application.
This article from one of my colleagues about analysis of the CPU-memory relationship in garbage collection shows and uses this new information.
JEP 516: Ahead-of-Time Object Caching with Any GC introduces a new mechanism for loading ahead-of-time (AOT) linked and loaded objects, with the explicit goal of working well with all Hotspot garbage collectors. The reason is garbage collection algorithm independent support of Project Leyden.
The previous AOT cache disk format was GC algorithm and VM option specific, which made extending it, particularly towards ZGC, difficult. The new format is GC-independent and independent of VM options.
The drawback is that the new algorithm requires more work at startup. The implementation of JEP 516 mitigates this startup impact by populating the objects concurrently to the application during startup.
To enable the new format, use the new -XX:+AOTStreamableObjects command line option.
Robustness of the shutdown process has been improved. Prior to JDK 26 it was possible for a JVMTI agent to allocate memory after the garbage collection subsystem had already shut down which could lead to unexpected behavior like hangs, out-of-memory errors or crashes.
Relevant issues include JDK-8367902 and JDK-8366865.
For a significant amount of command line options the defaults changed, or they have been deprecated for removal.
-XX:InitialRAMPercentage which determines the amount of the Java heap that is committed at startup based on a percentage of installed memory has been defaulted to 0. I.e. the amount of total memory installed is not relevant to initial Java heap size any more. (JDK-8371987).
In practice, the amount of memory is committed by the VM at startup (impacting startup time) now only follows the minimum heap size derived by other mechanisms (-XX:MinHeapSize/-Xms/-XX:InitialHeapSize and others), instead of arbitrarily initializing a percentage of installed RAM of your machine for the Java heap during startup.
The CSR for this change further details the reasoning for this change.
-XX:AggressiveHeap, which collects a set of optimizations mainly for “long-running memory-intensive benchmarking scenarios”, has also been deprecated. Multiple reasons including the generic name, its focus on SPECjbb, the complexity of finding a similar set of tunings for nowadays’ very diverse landscape of these applications led to its impending removal. The CSR lists the options it enables if one wants to recreate its effects manually.
The set of little known and typically only for internal testing used options that were deprecated for removal in...