Understanding JVM Garbage Collection: Serial and Parallel Collectors

Manjil Dahal
4 min readJul 16, 2024

--

In our previous article, we delved into the fundamental concepts of garbage collection and its major components. We discussed these components in isolation to build a foundation. In this article, we will examine one of the earliest collectors and see how these components work together to manage memory effectively and prevent memory issues. Our focus will be on the “Serial Collector” and “Parallel Collector”.

Serial Collector

The Serial Collector is a simple garbage collector that uses a single thread to perform garbage collection. It is suitable for single-threaded applications or small-scale applications with limited memory. The collector pauses the application (Stop-The-World, or STW) and then performs garbage collection in two phases:

  • Young Generation Collection (Minor GC)
  • Old Generation Collection (Major GC)
Generational Heap

Collecting the Young Generation (Minor GC)

The Young Generation contains newly created objects, so garbage collection in this area happens frequently due to the Generational Hypothesis. The first step in any garbage collection algorithm is to identify garbage. It starts with roots as its starting point and marks all reachable objects in the Young Generation. After marking, it copies all reachable (live) objects from the Eden space and the currently active survivor space to the inactive survivor space, then marks it as active. The Survivor space is divided into two sections, S1 and S2, where objects are copied from one section to the other in each cycle, toggling between active and inactive.

After this, all objects in the Eden region and the previously active (now inactive) survivor section are discarded, freeing up memory. The final step is updating references to the moved objects so that when the application resumes, it can access these objects despite their new memory locations.

This is possible because the application is completely paused during garbage collection, ensuring no race conditions or reference changes by other threads.

Young GC

Collecting the Old Generation (Major GC)

The Old Generation contains objects that have survived multiple cycles of Minor GC and have been promoted from the Young Generation. Major GC happens less frequently as it covers a larger section of the heap and can cause significant pause times. In the case of the Serial Collector, Major GC works similarly: it first marks all accessible objects from the roots, then moves them to another section of the heap to avoid fragmentation. Finally, it cleans up unreferenced objects and updates references to live objects in their new positions.

Old GC Post Marking

After completing the collection, the application resumes.

Parallel Collector

The Parallel Collector operates similarly to the Serial Collector but uses multiple threads for garbage collection. When STW occurs, it utilizes all available threads, allowing garbage collection to happen much faster. This makes it well-suited for multi-core systems and applications that prioritize throughput.

How Cross-Region References are Handled

We’ve explored simple cases of garbage collection, but what about cross-region references? For example, what if an object in the Young Generation is referenced by an object in the Old Generation? This scenario isn’t covered during a standard Young GC because it doesn’t look into the Old Generation to avoid slowing down the process. The solution is the Card Table.

Card Table

The Card Table is a data structure that helps the garbage collector manage cross-region references. It stores a collection of cards, each representing a block of memory in the heap. Each card contains a bit indicating whether it’s dirty (i.e., whether any object within the card’s memory is pointing to the Young Generation). When a reference from the Old Generation to the Young Generation occurs, the card’s bit is flipped from 0 to 1, marking it as dirty. This process uses a concept called Write Barrier.

Card Table

During Young GC, along with roots, the garbage collector checks entries in the Card Table which are dirty, processes all objects in locations referenced by dirty cards, and marks objects in the Young Generation referenced from the Old Generation as roots. This prevents GC from collecting them, solving the cross-region reference issue without a full scan of the Old Generation heap.

Summary

Serial Collector

  1. Predictability: Developers can anticipate pause times in each GC cycle.
  2. Small Heap Sizes: Ideal for managing smaller heaps.
  3. Single-Core Systems: Suitable for machines with a single-core CPU.
  4. Use Cases: Commonly used in client applications and environments with a small memory footprint, such as IoT devices.
  5. Performance: Low to moderate throughput, high latency, and low memory footprint.

Parallel Collector

  1. Multi-Core Systems: Used in machines with multi-core CPUs.
  2. Medium to Large Heap Sizes: Ideal for managing larger heaps.
  3. Batch Processing Systems: Suitable for systems where occasional pause times are acceptable but high throughput is essential.
  4. Performance: High throughput, moderate to high latency, and low memory footprint.

--

--