Advanced AOSP Subsystems
4 min read

Concurrent GC (CC GC)

Overview

This lesson dives into the Concurrent Copying (CC) Garbage Collector, the default and highly sophisticated GC algorithm used in modern Android versions (Android 8.0+). The CC GC was designed to virtually eliminate user-perceptible "jank" by drastically reducing Stop-The-World (STW) pauses.

The Problem with Fragmentation

Older collectors like Mark-Sweep suffered from heap fragmentation. To solve fragmentation, a collector must be a moving collector; it must compact the heap by moving live objects together.

However, moving an object changes its memory address. If the application is running concurrently, it might try to access the object at its old address, leading to a crash. Traditional moving collectors required long STW pauses to move objects and update all references safely.

The Concurrent Copying GC solves this by copying objects while the application is running.

Region-Based Heap

To support CC, ART divides the Java heap into smaller, fixed-size chunks called Regions (typically 256KB).

Instead of looking at the heap as one monolithic space, the GC manages these regions. During a GC cycle, it identifies "evacuation candidates" (regions that are mostly empty) and copies the live objects from these source regions into newly allocated, contiguous destination regions. Once copied, the entire source region is reclaimed at once, eliminating fragmentation.

The Read Barrier Technique

The magic that allows ART to copy objects concurrently without pausing the application is the Read Barrier.

A read barrier is a tiny snippet of code injected by the compiler (JIT or AOT) before every object read operation in the application.

When the application tries to read a reference field from an object, the read barrier intercepts the access:

  1. It checks if the GC is currently in an evacuation phase.
  2. It checks if the target object is in the process of being moved.
  3. If the object has already been moved, the read barrier intercepts the read, updates the reference to the new address, and returns the new object.
  4. If the object is actively being moved, the read barrier might block briefly or help with the copy.

Because the read barrier ensures the application always sees the most up-to-date address of an object, the GC can safely move objects in the background.

// AOSP reference: art/runtime/read_barrier.h
// Conceptual representation of a read barrier
template <typename MirrorType>
MirrorType* ReadBarrier::Barrier(MirrorType* obj) {
  if (IsMarking()) {
    return GetForwardingAddress(obj);
  }
  return obj;
}

GC Pause Reduction in CC GC

By moving the heavy lifting of copying objects and updating references to the concurrent phase (assisted by read barriers), the CC GC drastically reduces STW pauses.

In a typical CC GC cycle, the STW pauses are limited to:

  1. Brief initialization: Setting up the GC state.
  2. Brief flip phase: Switching thread roots to point to the new regions.

These pauses are typically on the order of a few milliseconds, well below the 16.6ms threshold required for smooth 60fps rendering, effectively eliminating GC-induced jank.

GC Log Analysis

Understanding how to read GC logs is critical for performance tuning. You can extract GC logs using Logcat.

adb logcat -s art

A typical CC GC log entry looks like this:

I art     : Background concurrent copying GC freed 12000(400KB) AllocSpace objects, 0(0B) LOS objects, 40% free, 15MB/25MB, paused 2.1ms total 110ms

Key metrics to analyze:

  • GC Reason: e.g., Background (normal threshold reached), Explicit (System.gc() called), Alloc (allocation failed, urgent GC).
  • Freed: Number of objects and total size reclaimed.
  • Heap State: e.g., 40% free, 15MB/25MB (current usage / total capacity).
  • Paused: The STW pause time (e.g., 2.1ms). In CC GC, this should remain very low.
  • Total: The total time taken by the GC cycle, including the concurrent background work (e.g., 110ms).