Skip to content
Coalescing Free Blocks
step 1/5

Reading — step 1 of 5

Read

~2 min readFree Lists

Coalescing Free Blocks

Splitting creates small blocks; programs free them at unpredictable times; and after enough churn a heap can hold plenty of free memory that is USELESS:

[free 50][used 100][free 50][used 200][free 100]

200 bytes are free, but the largest single free block is 100. ALLOC 150 fails while twice that much sits idle. This is external fragmentation — memory lost not inside blocks but BETWEEN them — and the antidote is coalescing: merging adjacent free blocks back into one.

free the [used 100] in the middle:
[free 50][free 100][free 50][used 200][free 100]
    \________|________/
[free 200][used 200][free 100]        ALLOC 150 now succeeds

When and how

Production allocators coalesce EAGERLY — at free time — because the neighbor checks are cheap if you can find the neighbors:

  • The NEXT physical block is easy: it starts at addr + size. Stepping forward by size is exactly how implicit-list allocators traverse the heap.
  • The PREVIOUS block is the hard direction — a size field only tells you how far FORWARD to step, not backward. The O(1) answer is Knuth's boundary tag: duplicate the size at the END of each block (a footer), so the predecessor's metadata sits at a fixed negative offset. That trick gets its own lesson (Boundary Tags).

Our simulator keeps blocks in an address-ordered list, so we can use a simpler tactic: after every FREE, one linear pass merges each run of consecutive free blocks. Merged sizes simply add — this model charges no per-block header on split, so there is none to reclaim on merge:

[108:100 free][208:100 free][308:716 free]   ->   [108:916 free]

The pass must collapse the WHOLE run — 100 + 100 + 716 — not just the first pair it meets. Freeing a block whose neighbors are BOTH free is precisely the case that turns three fragments into one.

Double-free is an error, not a merge

FREE is only legal on a currently-USED block. Test 4 frees address 8 twice: the first prints OK (and the block coalesces with the tail into 8:1016:free), the second must print BAD — there is a free block AT address 8 now, but it is not an allocated one. In C this exact mistake is a double-free vulnerability; glibc aborts with free(): invalid pointer when its integrity checks catch it. Your simulator gets to be the detector.

Your exercise

Test 2 is the three-way merge: allocate 100 three times (addresses 8, 108, 208, leaving tail 308:716), then FREE 108 and FREE 208. The grader expects BLOCKS to print exactly two lines: 8:100:used and 108:916:free. Three free lines (108:100:free, 208:100:free, 308:716:free) mean you never coalesced; 108:200:free followed by 308:716:free means your pass merges only one pair and missed the tail. Hidden test 7 frees in the order 8, then 208, then 108 — the middle-block-last order that only passes if freeing 108 merges BOTH directions at once, collapsing the whole heap back to a single 8:1016:free.

Discussion

Ask a question, share an insight, or help someone who’s stuck.

Sign in to post a comment or reply.

Loading…