ZGC: Making Java a more attractive platform for a wider set of applications
© Shutterstock / Pretty Vectors
The Z Garbage Collector (ZGC) was designed with the aim to remove obstacles that have previously hindered Java developers from getting access to innovations and new features. Now that the project is open source, anyone can try it out on their workloads. Let’s allow Per Liden, ZGC Lead, to tell us what’s under the hood of this new project and what’s next for ZGC.
JAXenter: Why did Oracle decide to make Z Garbage Collector open source? What was the end goal?
Per Lidén: Back in September, Oracle proposed to accelerate the JDK release cadence to six months and ultimately make OpenJDK binaries interchangeable with Oracle JDK binaries. The Oracle JDK has traditionally included commercial features that have not been available in OpenJDK. We intend to open-source such features and make them available in OpenJDK. The Z Garbage Collector (ZGC) is one such feature.
The end goal of all of this is to strengthen Java’s position as the number one development platform. We do this by removing obstacles that have previously hindered Java developers from getting access to innovations and new features.
ZGC — Making latency a non-issue for Java applications
JAXenter: What is the ZGC Project and what is its aim?
Per Lidén: Garbage collection is one of Java’s main strengths. However, when garbage collection pauses get too long they start to affect the applications’ response time negatively. By removing or drastically reducing the length of GC pauses, we’re making Java a more attractive platform for an even wider set of applications.
The ZGC Project is an independent project under the larger OpenJDK community. It’s the home for the continued development of the ZGC code base, with the primary goal of creating a garbage collector that can handle medium- to very large heaps, while maintaining very low GC pause times.
A secondary goal is to make GC tuning dead simple. Most of the current GCs in OpenJDK have a large set of tuning options to allow it to work well on a wide set of workloads. However, using these tuning options often requires a deep understanding or how the GC works internally and what tradeoffs you face. Most developers just want the GC to work, and work well, without having to acquire this knowledge. In the ZGC project, we’ve been striving to create a GC where the need for tuning is reduced, without sacrificing performance.
JAXenter: In the message to the OpenJDK mailing list, you said that you are currently working on making the remaining GC tasks/phases concurrent. Have you made any progress?
ZGC can already today offer very low pause times for many types of applications. We’re especially happy with ZGC’s ability to do reference processing concurrently.
Per Lidén: The remaining tasks I mentioned in the project proposal are things that typically involve JVM sub-systems other than ZGC. For example, we’re working on being able to concurrently (i.e. without stopping the execution of Java threads) unload unused Java classes. This requires significant changes to the JIT-compilers and the Runtime sub-system. Changes that span multiple JVM sub-systems will by their nature take some time to complete. We’re continuously making progress, but we’re not quite there yet.
Having said that, ZGC can already today offer very low pause times for many types of applications. We’re especially happy with ZGC’s ability to do reference processing concurrently. This means that your application can have as many Soft/Weak/Final/PhantomReferences as it wants without impacting GC pause times.
JAXenter: What is the key principle of ZGC?
Per Lidén: From a high level, the key to achieving low latency, especially when using very large heaps, is to have the GC operate concurrently with the execution of the Java threads. If an operation must execute while the Java threads are stopped (i.e. in a Stop-The-World phase), it’s critical that the time to complete such operation does not increase with the heap- or live-set size.
In ZGC, we’ve worked hard to make sure that any Stop-The-World phase will either execute in constant time, or in the worst case, increase with the root-set size. The root-set size roughly correlates with the number of Java threads running.
When looking at specific techniques used in ZGC, we believe the use of colored pointers in combination with a low overhead load barrier is a very powerful, yet simple, foundation and a key enabler for concurrency.
JAXenter: What are the advantages of using a combination of load barrier and colored object pointers compared to other alternatives?
Per Lidén: A concurrent garbage collector, like ZGC, needs to service allocation requests from the Java threads at the same time as it collects garbage and reclaims memory. This means that there must be enough headroom (i.e. free memory) in the heap to keep that cycle going. If a concurrent garbage collector can’t keep up and runs out of memory (i.e. heap gets full) it will have no choice but to stop, slow down, or in some other way impact the Java threads doing allocations. This is obviously bad for latency. The remedy for this is to give the GC a larger heap to work with (i.e. increase the headroom), but at the same time, you don’t want to waste memory.
For this reason, you want a concurrent garbage collector to be able to reclaim and reuse memory as quickly as possible. In ZGC, the use of colored pointers and load barrier allows us to reclaim and reuse memory already in the relocation/compaction phase, long before pointers pointing into the reclaimed/reused parts of the heap have been fixed/adjusted. Many garbage collectors typically require these dangling pointers to be fixed before the memory regions they point into can be reclaimed and reused for new allocations. This might sound harmless, but fixing these dangling pointers is typically an expensive operation which takes time to complete, and thus delays reclamation and reuse.
Keeping the runtime overhead of the load barrier to a minimum is another important aspect. In ZGC, executing a load barrier means executing a test and jump instruction sequence, which the branch prediction logic in modern CPUs handles very well. Further, ZGC uses the so-called “to-space invariant”, which among other things means that ZGC doesn’t need any store barriers and that the number of places in the code stream where it needs to inject load barriers is relatively limited.
By removing or drastically reducing the length of GC pauses, we’re making Java a more attractive platform for an even wider set of applications.
The combination of colored pointers and load barriers offers a versatile mechanism on which future features can be built. Today, ZGC stores marking and relocation-related information in the pointers, but we can essentially store any type of information there and let the load barrier use that information to take some special action. For example, this information could tell the load barrier that the object we’re loading is compressed or swapped out to cold-storage and that we need to un-compress or move the object to hot-storage. Other examples would be that information in the pointer can tell the load barrier that this object has been accessed since the last GC cycle (useful if you want to track heap access patterns), that this is a “weak” pointer, that the object it points to is a “young” object, that this is a “thread local” object, etc.
Exactly how ZGC will exploit this in the future remains to be seen, but we believe we have a very good foundation for many interesting features and optimizations going forward.
JAXenter: The initial source of the ZGC Project will be based on a clone of a JDK 10 repository, as well as the latest ZGC patch set. What will happen as the project gets closer to integration?
Per Lidén: We don’t know yet if, when, and how it will be integrated into the JDK itself. A pre-requisite for such decisions is to make it open source so that people can test and evaluate it. The feedback and discussions coming out of that will help guide how we proceed.
JAXenter: What’s next for ZGC?
Per Lidén: The project has been approved as an OpenJDK project. We hope that people interested in the project will try it out on their workloads and share their experiences. We will continue to work on and improve ZGC itself and the rest of the JVM, to make latency a non-issue for Java applications.