Mark-sweep reclaims garbage in place, which leaves survivors scattered with holes between them. Today you measure that fragmentation directly, motivating the compacting collector the rest of the chapter builds.
Show that after a mark-sweep collection the survivors do not form a contiguous block.
Mark-sweep has a cost that the exact-id specs make easy to see: it reclaims garbage
in place, so the survivors stay exactly where they were, and the freed slots become
holes scattered among them. After collecting a heap whose live objects were 0,
2, 4, the survivors are still at 0, 2, 4, with gaps at 1, 3, 5. Over
many cycles a heap fragments into a patchwork of live objects and holes - IsCompact
reports exactly that by checking whether the live objects fill a contiguous prefix.
Fragmentation hurts in two ways. It scatters related objects across the heap so they no longer sit near each other in memory, wrecking cache locality; and in a real allocator with variable-size objects it can leave enough total free space for a request that still cannot be satisfied because no single gap is big enough. The fix is compaction: move the survivors so they sit together with all the free space in one run. You cannot compact by nudging objects in place without breaking every reference to them, so the rest of this chapter builds a different kind of collector - one that compacts as a natural side effect of how it collects.
// the live objects are compact when they fill slots 0..Live-1 with no gapsfunc (h *Heap) IsCompact() bool {live := h.LiveRefs()for i, r := range live {if r != i { return false } // a hole: object should be at slot i but isn't}return true}