Core Java

GC Explained: Collectors Overview

The current version of HotSpot JVM includes three types of garbage collectors:

– Serial Collector

– Parallel Collector

– The Mostly Concurrent Collectors

All of them are generational ones, meaning that they take advantage of the way the heap is divided.

There are three main operations which garbage collector is responsible for:

– finding objects which are no longer used

– freeing up the memory after those objects

– compacting the heap

Not all the collectors perform those operations in the same way, so let’s go through the basic information about all of them. We will cover details in separate articles.

Serial Collector

As the name suggests, the collection is performed by only one thread. Stop-the-world (STW) pauses are necessary during both Minor and Full GC.

This collector uses the mark-copy algorithm for the Young Generation, whereas the Old Generation is cleaned up using the mark-sweep-compact algorithm.

Serial GC is designed for single-threaded environments (usually client-class machines) and for relatively small heaps. It can be enabled by -XX:+UseSerialGC flag.

Parallel (Throughput) Collector

The Young collection is parallelized by multiple threads which makes Minor GC much faster. As a result, this collector leads to shorter, but more frequent Young collection STW pauses. Since JDK 7u4, the Old Generation is also collected by multiple threads by default (and also causes stop-the-world pauses). Prior to JDK 7u4, -XX:+UseParallelOldGC flag was required to enable parallel processing of the Old Generation. Now, both -XX:+UseParallelGC and -XX:+UseParallelOldGC flags enable Throughput Collector with parallel processing of both the Old and Young Generations.

This collector also uses the mark-copy algorithm in the Young Generation and mark-sweep-compact in the Old Generation, but both copy and compact phases are executed by multiple threads.

To configure the number of GC threads you can use -XX:ParallelGCThreads=X flag. The default value is set to the number of CPU cores.

When is Parallel GC a good choice? Well, basically whenever throughput is more important than latency.

The Mostly Concurrent Collectors

They are so called low pause collectors – designed to minimize stop-the-world pauses and to keep the application as responsive as possible

Concurrent Mark and Sweep (CMS)

Minor GC is performed with multiple threads using the parallel mark-copy algorithm. All application threads are stopped then. The Old Generation is mostly collected concurrently – application threads are paused for very short periods of time when the background GC thread scans the Old Generation. The actual algorithm used during Major GC is concurrent mark-sweep. As you probably noticed, there is no “compact” after “sweep”. That’s true – Concurrent Mark and Sweep is the collector which doesn’t compact the Tenured space and thus the memory can be left fragmented. Due to lack of heap compaction, when GC is not able to fit new objects into the memory, JVM fallbacks to the serial mark-sweep-compact algorithm to defragment and compact the Old Generation. That’s when performance degradation comes – all application threads are stopped and just one single thread is responsible for cleaning and compacting the Tenured space.

As I mentioned earlier, CMS is an example of low pause collectors. It means that it’s a good choice when a latency is a primary target, not throughput – because throughput can be degraded due to increased CPU consumption (scanning the heap when application threads are running isn’t for free).

-XX:+UseConcMarkSweepGC enables CMS collector. It used to be possible to configure CMS with a single-threaded Young Generation collection using -XX:-UseParNewGC (notice minus before “UseParNewGC”, so by using this flag we disable Parallel New (Young) GC), but it has been deprecated in Java 8 and removed in Java 9.

G1GC

Garbage First (G1) is a new low-pause garbage collector designed to process large heaps with minimal pauses. The heap is broken down into several regions of fixed size (while still maintaining the generational nature of the heap). That kind of design allows us to get rid of long STW pauses when the entire Young or Old Generations are processed. Now, each region can be collected separately which leads to shorter, but more frequent STW pauses. G1 copies objects from one region into another, which means that the heap is at least partially compacted.

G1 uses an incremental version of the mark-sweep-compact algorithm. It can be enabled by specifying -XX:+UseG1GC flag.

Summary

Here is a simple comparison of the collectors discussed in this article:

CollectorMultiple GC ThreadsSTW (Young Generation)STW (Old Generation)Heap CompactionPrimary Goal
Serialnoyesyesyes
Parallelyesyesyesyesthroughput
CMSyesyesonly during scannolatency
G1yesyesvery short onespartiallylatency

There are some other garbage collectors out there, but they are not part of HotSpot JVM. These are:

  • C4 (Azul Zing JVM)
  • Shenandoah
  • Balanced (IBM J9 JVM)

In Java 8, a default GC for server-class machines is Parallel Collector. G1GC is going to be a default one in Java 9. Client-class machines run Serial Collector by default.

Reference: GC Explained: Collectors Overview from our JCG partner Grzegorz Mirek at the > performant code_ blog.

Grzegorz Mirek

Grzegorz is a software developer from Cracow, Poland. He started his adventure with Java roughly 6 years ago when he was at university and since that time, he keeps expanding his knowledge in this field. He is especially interested in JVM performance and optimisations and this is what he mostly blogs about.
Subscribe
Notify of
guest

This site uses Akismet to reduce spam. Learn how your comment data is processed.

0 Comments
Inline Feedbacks
View all comments
Back to top button