A request creates a new Order. A long-lived Customer object stores it in a field, then the request’s local reference disappears. When young memory fills, the collector must keep that Order: a reachable old object still points to it.
Lesson 22 separated tracing, which discovers live objects, from reclamation, which recovers space. Lesson 6 introduced generations, and Lesson 7 introduced the reference tracking that crosses them. Here we follow one young collection end to end. Its central question is: how can it find the young Order without scanning every old object?
To collect young safely, the collector must discover references into young from outside young without searching all of old.
An object’s path through generations
The young generation holds recent allocations. Objects that remain reachable through collection may enter a survivor area and eventually move to the old generation. That move is called promotion or tenuring. Many new objects never take the survivor branch: they become unreachable and their source space is reused.
Eden, Survivor, and Old name roles in that path. In HotSpot’s G1 collector, the heap is split into regions whose roles can change; the roles do not require three permanent, contiguous address ranges. G1 is the default on typical JDK 25 server-class configurations, although a selected collector and machine can differ.
Low survival makes young evacuation useful
Imagine 100 MB allocated into young regions, with 95 MB unreachable by the time collection starts and 5 MB live. An evacuating collection copies the live objects to destination regions, updates relevant references, then makes the source regions reusable. It does not copy the 95 MB of dead objects one by one.
The amount of surviving data often matters more to evacuation cost than bytes allocated alone. This is an intuition, not a pause-time formula. G1 also processes roots and incoming references, performs bookkeeping, and needs destination capacity for survivors.
The reference that young roots alone miss
Suppose Customer has survived long enough to reside in Old. A request runs customer.latestOrder = order, storing a reference to a young Order. Once the request’s local variable disappears, a trace of direct roots into Young misses Order; the live path runs through Old.
One way to discover that edge would be to scan every old object at every young collection. If Young is 500 MB and Old is 8 GB, repeatedly searching that 8 GB defeats much of the benefit of collecting only Young. The collector instead records where relevant reference changes happened while the application runs.
The application threads that update the object graph are mutators. A write barrier is a small piece of runtime bookkeeping associated with a reference update. The post-write side considered here records information useful for finding incoming references; it does not perform a garbage collection at each assignment.
A card marks a range, not a pointer
A card is a small logical range of heap addresses. A card table associates metadata with those ranges. If the reference slot in Customer changes, barrier bookkeeping can mark its source card dirty: this range is interesting and may need inspection. The card is based on the address of the modified slot, not necessarily the start of its containing object. A large object can span cards.
The reference might be overwritten before that range is examined. Several slots may share one card. The mutator can record the candidate cheaply; collector-side refinement can inspect it later. Correctness requires pending changes to be accounted for before a collection relies on the remembered information.
A remembered set answers a different question: which source locations outside the selected collection set may contain references into it? In G1, its entries are approximate source locations represented with cards, not a list of exact pointer addresses. Refinement can turn a dirty source card into remembered information for a target region or region group. Processing a dirty card does not erase a still-relevant incoming edge.
A dirty card says “inspect this changed range”; a remembered-set entry says “this outside range may point into the collection set.” Both are conservative. Scanning a candidate card can add work; missing a required incoming edge could incorrectly discard a live object.
Follow one young collection
G1’s collection set is the group of source regions selected for a pause. For a young collection, think of the selected Eden and survivor regions as the target. The collector starts from ordinary roots, such as live execution and runtime references, and also scans the outside source locations identified by remembered information. The old Customer card supplies the edge to the young Order.
It then traces the reachable young graph, leaves unreachable objects behind, evacuates survivors to destination regions, repairs the relevant references, and reuses the evacuated source regions. A survivor may remain young in a survivor region or promote into Old. G1 uses remembered locations as roots into the collection set; its regional model generalizes our old-to-young example to outside the collection set → inside the collection set.
The path is a teaching model. Actual G1 pauses assemble and process remembered information, coordinate reference updates, and handle exceptional cases. Cards and remembered sets reduce broad old-heap scanning; they do not eliminate root work or all collector-side scanning.
Promotion follows pressure and policy
Object age matters, but “survive exactly N collections, then promote” is too rigid. Collector heuristics and age thresholds, survivor capacity, object characteristics, available destination regions, and current heap conditions can influence whether an object stays young or moves to Old. Promotion itself consumes space and copies or otherwise handles the survivor; it is not a free change of label.
Consider two illustrative services allocating 1 GB/s. In A, 98% of a cohort dies before collection. In B, 50% survives. B asks the collector to trace and evacuate far more live data and may send more of it into Old. Its old occupancy can rise even when every young collection succeeds.
Barrier execution adds mutator-side work; card refinement, remembered-set maintenance, and scanning candidate cards add collector-side work and metadata cost. That trade is useful when it avoids repeatedly scanning much larger areas outside the collection set. When many cards are relevant, remembered-set work can itself become significant.
Check your reasoning
A root reaches an old Customer, which points to a young Order. Why is tracing only direct roots into Young unsafe?
The live path crosses Old. Without an incoming-reference record or an Old scan, the young trace could miss Order and reclaim it incorrectly.
A card was marked dirty, then its reference field was overwritten. Does dirty prove a young object is still referenced?
No. Dirty identifies a changed address range that needs processing. Refinement examines current references; remembered information for a collection target may remain even after the dirty state is cleared.
Two services allocate equally, but one promotes much more data. Which additional signals help explain its GC pressure?
Compare survival, promotion, live-set size, old occupancy trend, available evacuation headroom, collection work, and latency. Allocation rate alone cannot explain the difference.
The path into G1 internals
Young collection works because ordinary roots and remembered outside references together expose the young live set. Dead objects stay behind; survivors evacuate to survivor or old destinations; source regions become reusable. Partial collection depends on preserving incoming-reference knowledge across the collection boundary.
Lesson 24 examines G1’s regions, collection sets, evacuation pauses, remembered-set work, concurrent marking, mixed collections, and selection of old regions. This lesson has focused on the post-write/reference-update barrier for remembered-reference maintenance. G1’s SATB barrier supports concurrent marking and will receive its full explanation in Lesson 25.
Sources and implementation boundaries
Based on Daily JVM Byte #23 and the reviewed lesson draft. Heap sizes, cohort percentages, diagrams, and the Customer/Order path are illustrative; no GC workload or command was run for this lesson. Region roles, card-based remembered entries, evacuation, and barrier descriptions refer to HotSpot G1 on JDK 25, not Java language guarantees or every JVM collector. Actual phase scheduling, barrier optimization, age policy, and destination choice vary with collector and configuration.