An In-Depth Look At Java Garbage Collectors

0
3

Let’s dive into the various types of garbage collectors available in Java and lay out a side-by-side comparison to help you choose the right one for your workload.

Garbage collection is an essential pillar of Java’s memory management, silently reclaiming unused memory and keeping your application healthy. With each new edition of the Java platform, OpenJDK introduces refinements to how garbage collectors work, aiming for better performance, reduced latency, and improved scalability.

At its core, a garbage collector (GC) frees up memory by automatically removing unused objects, sparing developers the burden of manual memory management. Different applications have different requirements—some demand lightning-fast throughput, others need minimal pause times, and some are designed for massive heap sizes. Java’s GC options have grown to accommodate these diverse needs.

A tour of Java’s garbage collectors

Let’s look at the main types of garbage collectors available in OpenJDK and how they fit into today’s Java ecosystem.

Serial GC

Serial GC is the simplest of the bunch, designed for single-threaded environments. It performs all garbage collection tasks in a single thread, making it suitable for small applications or embedded devices where resources are limited. While its implementation is straightforward, its stop-the-world pauses aren’t ideal for large-scale or interactive applications.

Parallel GC (Throughput Collector)

Parallel GC, sometimes called the Throughput Collector, utilises multiple threads to speed up the garbage collection process. It’s optimised for throughput, meaning it tries to maximise the amount of work done in a given time, even if that means longer pause times. This collector is often used for applications running on multicore processors that can afford occasional interruptions.

Concurrent Mark Sweep (CMS) GC

CMS was designed to minimise pause times by performing most of its work concurrently with the application threads. It marks live objects while the application is running and sweeps away the dead ones. However, CMS can suffer from fragmentation and isn’t recommended for future projects since it’s been deprecated and removed from newer Java versions.

Garbage First (G1) GC

G1 GC is a modern collector that strives to balance throughput and low latency. It divides the heap into regions and prioritises areas with the most garbage to collect first. G1 is adaptive, tuning its behaviour based on pause-time goals you set. It’s the default collector for most contemporary Java applications and continues to evolve with each Java release.

Epsilon GC

Epsilon is a ‘no-op’ garbage collector. It doesn’t reclaim memory—it simply allocates until the process runs out of heap space. This collector is useful for performance testing or scenarios where memory management is handled externally.

Z Garbage Collector (ZGC)

ZGC is a scalable, low-latency collector designed to handle massive heaps (think multi-terabyte scale) with minimal pauses. It carries out most of its work concurrently, pausing application threads only briefly. ZGC is suitable for cloud workloads, large in-memory databases, and applications that cannot tolerate significant interruptions.

Shenandoah GC

Like ZGC, Shenandoah is focused on ultra-low pause times, even as heap sizes scale into terabytes. Shenandoah performs concurrent compaction, further reducing pause times compared to traditional collectors. It’s particularly attractive for applications demanding high responsiveness.

GC type Threading model Pause time Heap size support Throughput Fragmentation handling Recommended for Concurrent

compaction

Serial GC Single thread High (stop-the-world) Small Low Poor Small apps, single-core systems No
Parallel GC Multi-threaded Moderate Medium-Large High Moderate Batch processing, multicore systems No
CMS GC Multi-threaded (concurrent) Low Medium-Large Moderate Poor (fragmentation possible) Low-latency apps (deprecated) No
G1 GC Multi-threaded (concurrent + parallel) Configurable (low to moderate) Large High Good
(region-based)
General purpose, latency-sensitive apps Partial
Epsilon GC Single thread None (no collection) Small-Medium Highest (no GC overhead) N/A Testing, custom memory management No
ZGC Multi-threaded (concurrent) Very low (<2ms) Huge (>4TB) High Excellent Large heaps, real-time, cloud Yes
Shenandoah GC Multi-threaded (concurrent) Very low (<10ms) Huge (>4TB) High Excellent Large heaps, low latency Yes

What’s new in Java 25 garbage collection?

Java 25 introduces several notable enhancements to garbage collection:

ZGC improvements

ZGC now features even shorter pause times and better support for thread-local allocation buffers (TLABs), leading to more predictable latencies for real-time applications.

Shenandoah enhancements

Shenandoah now supports improved handling of large objects and more efficient concurrent compaction, which reduces heap fragmentation and boosts allocation performance.

G1 adaptive tuning

G1 GC introduces new adaptive heuristics to better balance throughput and pause time, especially in workloads that fluctuate between bursty and steady-state memory allocation patterns.

Unified logging

Java 25 brings unified and more granular GC logging, making it easier for developers to analyse memory behaviour and tune GC settings for their specific needs.

Better native memory tracking

Enhanced monitoring tools now allow for more accurate tracking of native memory usage alongside heap consumption, which helps in diagnosing leaks and optimising performance.

Recommended command-line usage

Here are the recommended scenarios for each garbage collector in Java 25 and its command-line usage.

Serial GC

Recommended scenario: This garbage collector is best for small apps with limited CPU resources.

Command-line usage:

java -XX:+UseSerialGC -jar test-application-name.jar

Parallel Garbage Collector

Recommended scenario: Parallel GC is suitable for any multi-threaded application where throughput is a primary consideration.

Command-line usage:

java -XX:+UseParallelGC -jar test-application-name.jar

Concurrent Mark Sweep (CMS) Garbage Collector

Recommended scenario: CMS GC works mainly on the old (tenured) generation and uses multiple threads to mark and sweep unused objects.

Command-line usage:

java -XX:+UseConcMarkSweepGC -jar test-application-name.jar

G1 (Garbage First) Garbage Collector

Recommended scenario: This option is most suitable for applications that require consistent pause times and manage large memory heaps.

Command-line usage:

java -XX:+UseG1GC -jar test-application-name.jar

Z Garbage Collector (ZGC)

Recommended scenario: This GC is designed for applications requiring minimal pause times and large heaps.

Command-line usage:

java -XX:+UseZGC -jar test-application-name.jar

Shenandoah Garbage Collector

Recommended scenario: This GC is suitable for low-latency applications with large heaps.

Command-line usage:

java -XX:+UseShenandoahGC -jar test-application-name.jar

Epsilon Garbage Collector

Recommended scenario: Epsilon is suitable for performance testing and benchmarking scenarios where memory reclamation is not required.

Command-line usage:

java -XX:+UseEpsilonGC -jar test-application-name.jar

The table above summarises the key characteristics of each garbage collector discussed above. This should help you match a collector to your specific application needs.

Java’s garbage collectors have evolved to meet a wide variety of demands, from tiny embedded systems to sprawling cloud services that require heaps spanning terabytes. Java 25 continues this tradition, refining the latest collectors to be even more responsive and powerful. As you select a GC for your next Java project, weigh your application’s needs for performance, pause time, and heap size support, and don’t forget to keep an eye on the latest improvements—these can make a real difference in your application’s stability and responsiveness.


Disclaimer: This article expresses his views and not of the organisation he works in.

LEAVE A REPLY

Please enter your comment!
Please enter your name here