skip to content

Region-Based (Garbage-First) Collector

The default collector: a region-based design that meets a soft pause-time target by collecting the regions with the most garbage first, using a concurrent marking cycle, mixed collections, and per-region remembered sets. Interviewers expect you to know the default in detail, including how humongous objects and the pause-time goal change its behavior.

on this pageshow

questions

5

The Garbage-First collector is named for the order in which it reclaims memory. Explain what 'garbage first' means in practice and how the collector chooses which heap regions go into the next collection set.

level: middleimportance: must knowfreq 55%

answer

  1. cost = live bytes, reward = whole region
  2. sort old regions by garbage, take richest first
  3. young regions always in the CSet
  4. liveness comes from the concurrent marking cycle
  5. live threshold 85%, count target spreads mixed GCs

basics

~20 s

G1 tracks how much live data each region holds. For a given pause it collects all young regions plus, in mixed collections, the old regions with the least live data - the most garbage - because evacuation cost scales with live bytes, so those regions give the most free space per millisecond spent.

solid answer

~50 s

G1 collects by copying live objects out of a region and freeing the region whole, so the cost of collecting a region is proportional to its **live** data, while the payoff is the region's **garbage**. Ranking regions by garbage-per-unit-cost and taking the best ones first is what 'garbage first' means. The concurrent marking cycle computes a liveness estimate for every old region. G1 then builds a **collection set** for each pause. Young regions are always included - they cannot be skipped, because G1 does not track references into young regions individually. In a **mixed** collection G1 adds old regions from the sorted candidate list, richest in garbage first, adding regions only while its prediction model says the pause will still fit the pause-time goal. Regions whose live occupancy exceeds a threshold (`-XX:G1MixedGCLiveThresholdPercent`, 85 by default) are not worth evacuating and are skipped. `-XX:G1MixedGCCountTarget` spreads the candidate set over several mixed collections instead of one giant pause.

code

text · 4 lines
text
-XX:MaxGCPauseMillis=200          # soft pause goal; bounds how many old regions fit in a CSet
-XX:G1MixedGCLiveThresholdPercent=85  # skip old regions denser than this in live data
-XX:G1MixedGCCountTarget=8        # spread the candidate old regions over ~8 mixed collections
-XX:G1HeapWastePercent=5          # stop mixed collections once reclaimable heap falls below this

go deeper

for a junior

Know that G1 prefers to collect regions containing the most garbage because copying only the few live objects is cheap.

for a middle

State the cost model (work scales with live data, reward is the whole region), that liveness comes from concurrent marking, and that young regions are always in the collection set.

for a senior

Discuss how the pause goal bounds how many old regions enter each mixed collection, the live-threshold and count-target knobs, and the failure mode when no region is garbage-rich enough.

for a principal

Position it as a scheduling policy over a heterogeneous work queue: profitability-ordered selection under a latency budget, whose degradation path is starvation of reclamation and fallback to a full collection.

## The cost model that gives the collector its name G1 reclaims a region by evacuating it: every live object inside is copied elsewhere, references to it are updated, and then the whole region is returned to the free list. Two facts follow. First, the *work* of collecting a region is proportional to the number of live bytes it contains - copying is the dominant cost, plus the references that must be fixed up. Second, the *reward* is the whole region: the garbage in it costs nothing to reclaim, because nothing is done to dead objects at all. That asymmetry is the entire idea. A region that is 5% live yields 95% of a region of free space for 5% of a region's worth of copying. A region that is 90% live yields almost nothing for almost the full copying cost. So if you must fit collection into a bounded pause, you should sort regions by how much garbage they yield per unit of work and take the best ones first. Hence Garbage-First. ## Where the liveness numbers come from G1 cannot know a region's live data without marking. The concurrent marking cycle traces the object graph while the application runs and, at its end, records a per-region live-bytes figure. Those figures are what the collector sorts on. This is why old regions become collection candidates only after a marking cycle has completed: before that, G1 has no basis on which to rank them. ## Building a collection set Every G1 pause evacuates a **collection set** (CSet), a chosen set of regions: - **Young-only collection**: the CSet is all eden and survivor regions. Young regions are mandatory. G1 keeps remembered sets that record references *into* old regions, not into young ones, so it cannot evacuate some young regions while leaving others behind; the young set goes as a unit. G1 controls cost here by controlling how large the young set is allowed to grow before a pause is triggered. - **Mixed collection**: the CSet is all young regions plus a selection of old candidate regions. G1 walks the candidate list from most garbage to least, adding regions while its pause prediction still fits the target given by `-XX:MaxGCPauseMillis`. Two limits shape it: `G1MixedGCLiveThresholdPercent` (default 85) excludes regions that are too densely live to be worth copying, and `G1MixedGCCountTarget` (default 8) spreads the candidates across several mixed collections so no single pause tries to absorb them all. Since JDK 12, an in-progress mixed collection can also abort part-way if the prediction turns out to be wrong. ## Why the young set is not ranked Candidates for ranking are old regions only. Young regions are typically mostly garbage anyway (the vast majority of objects die young), so collecting all of them is nearly always a good deal - the ranking machinery would add cost without adding much choice. ## What this buys and what it costs The benefit is that old-generation reclamation becomes incremental and steerable: instead of one operation whose cost scales with the whole old generation, G1 performs many bounded operations, each choosing the most profitable work available. The cost is that low-garbage regions may never be selected. If a heap fills with regions that are dense with long-lived data, G1 cannot reclaim enough per pause, allocation outruns reclamation, and the collector falls back to a full collection. That is the failure mode to name when asked what happens when garbage-first selection stops working.

  • Why can G1 not simply pick a subset of young regions the way it picks old ones?
    Because its remembered sets only record references pointing into regions that might be collected independently, and G1 deliberately does not maintain per-region records of references into young regions - that would make the write barrier far more expensive. Without those records it cannot find all roots for a single young region, so the entire young set is evacuated together and cost is controlled by capping young size instead.
  • What happens when every old region is too densely live to be a good candidate?
    Garbage-first selection has nothing profitable to choose, so mixed collections reclaim little. If allocation continues, G1 exhausts free regions and falls back to a full, whole-heap compacting collection, which is exactly the long pause the design was meant to avoid. In practice this shows up as rising heap occupancy after mixed cycles, then a full GC in the log.

Clearing storage lockers where you must personally carry out anything still wanted. You empty the near-empty lockers first: minimum carrying, maximum space freed. The locker packed to the ceiling stays, because emptying it costs a full day and frees the same single locker.

saying these in an interview costs you the question

  • Saying G1 collects the oldest regions first - it collects the emptiest ones first, regardless of age.
  • Claiming G1 can skip individual young regions to shorten a pause.
  • Believing old regions can be ranked before any concurrent marking cycle has completed.
  • Assuming a region that is 100% live is still worth evacuating; G1 deliberately skips dense regions.
  • Treating -XX:MaxGCPauseMillis as a hard limit that selection can always satisfy.

context

open as a page

The HotSpot Garbage-First (G1) collector divides the Java heap into regions instead of contiguous young and old spaces. Explain how that layout works and what eden, survivor, old, and humongous regions mean.

level: middleimportance: must knowfreq 62%

basics

~20 s

G1 splits the heap into equal-sized regions (a power of two, 1-32 MB, roughly 2048 of them). Each region is tagged at runtime as eden, survivor, old, or humongous. A generation is the current set of regions with that tag, not a contiguous address range.

open as a page

Walk through the phases of the HotSpot G1 collector's concurrent marking cycle, from what triggers it to what it produces, and explain how its output is used afterwards.

level: seniorimportance: should knowfreq 45%

basics

~20 s

Heap occupancy crossing a threshold starts the cycle: initial mark (piggybacked on a young pause), concurrent root-region scan, concurrent mark, a short stop-the-world remark, then cleanup. It produces per-region live-data counts, frees entirely empty regions immediately, and builds the old-region candidate list for mixed collections.

open as a page

The G1 collector can evacuate a single old heap region without scanning the rest of the heap. Explain the per-region remembered sets that make that possible, how they are kept up to date, and what they cost.

level: seniorimportance: should knowfreq 42%

basics

~20 s

Each region has a remembered set listing where references into it come from, recorded as card-table cards in other regions. Evacuating a region means scanning its remembered set instead of the whole heap. Updates flow from a post-write barrier through dirty-card queues to refinement threads; the cost is memory plus barrier and refinement CPU.

open as a page

The Garbage-First collector accepts a pause-time goal via -XX:MaxGCPauseMillis, but the goal is explicitly soft. Explain the machinery behind it and how you would reason about a service whose latency requirement is stricter than what that goal delivers.

level: principalimportance: should knowfreq 38%

basics

~20 s

G1 keeps statistics on past pauses and predicts the cost of evacuating candidate regions, then sizes the young generation and the collection set so the predicted pause fits the goal. It is a prediction, not a guarantee: mispredictions, humongous allocation, evacuation failure, and full GCs all overshoot it.

open as a page