5.3.2 · Maintaining the illusion of infinite memory
Copy live cells, forward repeated references, and leave garbage behind.
Move the graph reachable from an explicit root set into a fresh vector memory, installing forwarding pointers that preserve shared tails and cycles.
Guiding question
How can a collector compact live storage without duplicating shared objects or looping forever through a cycle?
Distinguish from-space from an initially empty to-space
Copy only pair pointers reachable from the supplied roots
Install a forwarding entry before recursively copying fields
Reuse one new pointer for every repeated reference to an old cell
Preserve a cycle by recognizing a forwarded pointer
Measure reclaimed cells and the advancing free pointer
copy-value returns atoms unchanged. For a pair pointer, it first consults forwarding by old index. A missing entry allocates one placeholder cell in to-space and records the new pointer before either field is followed. The car and cdr are then copied recursively into that placeholder. Recording first is what makes both sharing and cycles finite.
The first heap has five allocated cells but only three are reachable from the two roots. The copied left and right cells point to one copied shared tail, while both garbage cells retain false forwarding entries. The second heap contains a self-cycle; copying the cdr reaches the old pointer again and immediately reuses the already installed new pointer. This finite program performs one explicit collection within a fixed semispace capacity.
The shared-graph collection returns (5 3 2 (a shared) (b shared) #t #f #f). The cyclic collection returns (1 node #t #f).
Trace focus
In the shared graph, follow the first old shared pointer into a new allocation and the second occurrence into the existing forwarding entry. Confirm that old indexes 3 and 4 are never visited. In the cycle, locate the forwarding write before the recursive cdr copy reaches the old node again.
Try it yourself
Change the program and compare the result.
Add a third root that points directly to the shared tail, then mutate the copied tail. Predict the new allocation count and every root observation. Next swap the semispaces and allocate one additional cell.
Show hint
An extra root to an already forwarded object adds no copied cell. After collection, all clients must use the rewritten roots in to-space rather than stale from-space pointers.