Note [Aging under the non-moving collector]
The initial design of the non-moving collector mandated that all live data
be evacuated to the non-moving heap prior to a major collection. This
simplified certain bits of implementation and eased reasoning. However, it
was (unsurprisingly) also found to result in significant amounts of
unnecessary copying.
Consequently, we now allow "aging", allows the preparatory GC leading up
to a major collection to evacuate objects into the young generation.
However, this introduces the following tricky case that might arise after
we have finished the preparatory GC:
moving heap ┆ non-moving heap
───────────────┆──────────────────
┆
B ←────────────── A ←─────────────── root
│ ┆ ↖─────────────── gen1 mut_list
│ ┆
╰───────────────→ C
┆
In this case C is clearly live, but the non-moving collector can only see
this by walking through B, which lives in the moving heap. However, doing so
would require that we synchronize with the mutator/minor GC to ensure that it
isn't in the middle of moving B. What to do?
The solution we use here is to teach the preparatory moving collector to
"evacuate" objects it encounters in the non-moving heap by adding them to
the mark queue. This is implemented by pushing the object to the update
remembered set of the capability held by the evacuating gc_thread
(implemented by markQueuePushClosureGC)
Consequently collection of the case above would proceed as follows:
1. Initial state:
* A lives in the non-moving heap and is reachable from the root set
* A is on the oldest generation's mut_list, since it contains a pointer
to B, which lives in a younger generation
* B lives in the moving collector's from space
* C lives in the non-moving heap
2. Preparatory GC: Scavenging mut_lists:
The mut_list of the oldest generation is scavenged, resulting in B being
evacuated (aged) into the moving collector's to-space.
3. Preparatory GC: Scavenge B
B (now in to-space) is scavenged, resulting in evacuation of C.
evacuate(C) pushes a reference to C to the mark queue.
4. Non-moving GC: C is marked
The non-moving collector will come to C in the mark queue and mark it.
The implementation details of this are described in Note [Non-moving GC:
Marking evacuated objects] in Evac.c. References 0
This Note does not link to any other.