Charge Vertical Scaling With the Latest Java GCs
The latest generations of GC bring far-reaching consequences for running Java applications. This article intends to highlight the effects of ZGC and Shenandoah.
Join the DZone community and get the full member experience.
Join For FreeIn the dynamic landscape of Java ecosystem enhancements, one could miss an important progress that has been made in Java Garbage Collection (GC) in recent years. Meanwhile, the latest generations of GC bring far-reaching consequences for running Java applications. This article intends to highlight the significant effects brought to us by ZGC and Shenandoah.
Garbage Collection
Garbage Collection is a feature that distinguishes Java from many other programming languages. The GC mechanism exempts manual memory management from development routine via finding and removing objects no longer used by an application automatically.
However, one should dive deeper into the CGs’ operational principals to choose the CG suitable for the goals of the application to optimize the code's performance and avoid common memory-related errors; especially when there’s a variety of Garbage Collectors available for Java run, serving to optimize various indicators at the expense of different overhead costs.
The GC works in parallel with the application, and as such, it competes with the application for internal resources. The GC in a Java application fulfills a number of roles:
- Allocates memory for new objects
- Watches out for which objects are reachable by the application through a chain of references in the heap
- Frees up those that aren't
By performing these functions, the GC cleans up the memory automatically.
If with old generations of GCs, we got used to some level of glass ceiling for potential scaling, the modern GCs are changing the Java practice, delivering a vertical scaling that was previously unavailable.
JVM Memory Structure
Heap is part of a Java program memory where objects are stored. Objects that are no longer needed are called garbage. JVM manages this memory freeing space that is no longer required and places alive objects in an optimal way. This process is called Garbage Collection.
The Java heap is divided into several generations, each serving different purposes to optimize memory management and Garbage Collection.
Here is a short list of CG generations in Java:
- Young Generation for newly created objects
- Old Generation for long-term objects that arrive here from the young generation area after surviving several circles of GC
- Metaspace (replacement for PermGen used in mature LTS versions), storing metadata of classes and methods: It differs from PermGen in its ability to expand dynamically. Even though it has dynamic expansion, its maximum size can be controlled with the JVM setting, allowing management of memory consumption for metadata.
Assembly of different generations varies and does not necessarily occur at the same time. For garbage collectors (GC), the source of their existence is the weak generational hypothesis (most objects die young).
Various types of GCs require different settings specific to the application's goal metrics. The correct setup of metrics ensures a high level of Java application efficiency. Memory management depends on those settings, and switching them on per individual need delivers optimized memory management. GCs, though, carried some restrictions and had to take pauses in their work, which in large complex applications might lead to delays in operation.
GCs serve to ease Java development. Various types of GCs require settings tailored to a given application's goal metrics. The correct setup ensures a high level of Java application efficiency. Memory management depends on those settings, and switching them on per individual need delivers optimized memory management.
How ZGC and Shenandoah Change Java Run
With the growing number of application users and massive, complex Java workloads, the old GCs sometimes could not cope with modern data volumes, leading to noticeable pauses in an application's work or increased memory usage and OutofMemoryError
messages (when the JVM or another platform runs out of memory while trying to run an application).
As Java coding became increasingly complex, two new GCs were designed to overcome the setbacks of older GC tools: ZGC and Shenandoah.
Z Garbage Collector
Z Garbage Collector (ZGC) was introduced as an experimental collector in Java 11, and with the implementation of JEP-377, it became a production-ready feature in JDK 15.
ZGC is made to manage massive memory volumes that are common in modern applications. Today's Java applications carry large amounts of memory, and managing this memory requires GC to possess enhanced technological skills.
The ZGC is a scalable, low-latency garbage collector that can perform all expensive work concurrently without stopping the execution of application threads for more than 10ms. It is suitable for applications requiring ultra-low latency or using a large heap (multi-terabytes).
ZGC outstands older GCs, activating a complex process for each of these stages:
- Reference coloring to storing the reference state
- Applies load barriers to check the metadata bits of the reference
- Based on the colored referencing and load barriers, it performs remapping, creating a different reference.
- Relocates memory in parallel with the application
Shenandoah GC
Shenandoah GC is a garbage collector that aims to minimize pause time. This time increases due to processes of running memory evacuation in parallel with running Java threads. Shenandoah carries a feature that allows independence of GC pause times. So, the pause times are equally short for a 200 MB and a 200 GB heap. Shenandoah achieves this stability via an additional indirection pointer for each Java object, which allows GC threads to compact the heap while Java threads continue to execute.
Shenandoah GC is included in product functions starting from JDK 15. Its key characteristics are:
- Concurrency: It runs in parallel with the application and compacts concurrently, thus avoiding fragmentation issues.
- Operation in 3 or 2 concurrent phases, where the traversal phase (or traversal mode) was deprecated
- Aiming for <10ms pauses
-
Location-based GC, enabling Shenandoah to collect each region independently without remembered sets.
The Shenandoah garbage collector is suitable for applications where short garbage collection pauses are essential, regardless of heap size.
Effective Java Run and Larger Vertical Scaling
To better understand the effects brought to the Java ecosystem by ZGC and Shenandoah, let's review the roots of the problems they were designed to cure.
The low latency of older GCs is linked to long pauses in the GCs' work and large heap sizes. These two metrics have been growing together with application complexity. Plus, the invisible barrier to Java scaling was partly due to hardware limitations. Quite recently, a memory of 20 gigabytes was considered large, and today we operate in terabyte measurements. The technology evolved for both software and hardware, offering extensive memory sizes for new scaling horizons.
We have entered the new reality of software development with expanded hardware capabilities. To effectively use today's memory volumes, we can take existing Java code and libraries and scale them by upgrading and migrating Java applications. To arrange this scaling, companies need development teams and resources.
Modern GCs deliver an alternative path to achieving the same results. Using ZGC and Shenandoah allows the same scaling without code rewriting, extra resources, and development team involvement. Now, businesses can stay on the same applications and just add a relevant GC for more effective Java runs.
Scaling Java workloads via code rewrite is a complex process that requires special expertise. However, as the GC settings are located inside the JVM, businesses have easy access to these quality instruments, allowing for vertical scaling in a convenient inexpensive manner.
ZGC and Shenandoah are great instruments, showing where the Java evolution is heading today. Modern Java development uses easy and convenient tools to increase application efficiency without requiring extra budgets or deep expertise.
A further improvement to existing ZCG and Shenandoah is coming in the generational GCs. Generational GC works on improved algorithms and allows memory usage and pause reductions to be decreased. They are focused on cleaning short-living memory in the young generation. The generational approach further optimizes the garbage collection process. To choose a GC that is the perfect fit, you may require a consultation with your OpenJDK vendor; it is the quickest path for quality Java vertical scaling available today.
Opinions expressed by DZone contributors are their own.
Comments