Once the survivors are copied and their references fixed, the two spaces swap roles. Today you build the flip - to-space becomes the active space and the old space is cleared - the step that makes a copying collection permanent.
Swap the semispaces so the compacted copies become active and the old space is reset.
After copying and scanning, every live object has a compacted copy in to-space and every reference points there; from-space holds nothing but corpses and forwarding notes. The flip makes it official: swap the two halves so to-space becomes the active space, set the allocation cursor to where copying stopped (survivors occupy the prefix, free space is the contiguous run after them), and wipe the old half so it is a clean reserve for next time.
This is where the copying collector pays off. Because the survivors were bump-copied
into to-space from slot 0, they come out compacted - no holes, all free space in one
block - which is exactly the fragmentation cure Chapter 4 opened with. The old space’s
scattered layout simply ceases to exist. The one thing the flip does not do is
update the roots; they must be pointed at the copies during the collection itself,
which is the last piece the next lesson assembles into a full Collect.
func (h *CopyingHeap) flip() {h.from, h.to = h.to, h.from // to-space becomes the active spaceh.next = h.toNext // keep allocating after the copied survivorsfor i := range h.to { h.to[i] = nil } // wipe the old space; it is the new reserveh.toNext = 0}