Worked examples — Memory allocation — contiguous (first-fit, best-fit, worst-fit)
Before we start, one symbol we lean on constantly:
The scenario matrix
Every case a contiguous-allocation problem can throw at you is one of these cells. Each worked example below is tagged with the cell(s) it covers.
| Cell | Case class | What is unusual | Covered by |
|---|---|---|---|
| C1 | Exact fit (, leftover ) | hole vanishes entirely | Ex 1 |
| C2 | Tie — two holes equally "best" or "worst" | tie-break rule (lowest address) | Ex 2 |
| C3 | Request fails: no hole big enough | allocation returns failure | Ex 3 |
| C4 | Fails despite total free ≥ request | fragmentation, not shortage | Ex 3 |
| C5 | Zero / degenerate input (, empty free list) | boundary behaviour | Ex 4 |
| C6 | Sliver accumulation (best-fit worst case) | tiny dead leftovers pile up | Ex 5 |
| C7 | Big-hole starvation (worst-fit weakness) | large future request starves | Ex 6 |
| C8 | Same workload, all 3 rules diverge | rule choice changes success | Ex 7 |
| C9 | Real-world word problem (parking lot / disk) | translate story → holes | Ex 8 |
| C10 | Exam twist: 50% rule / after a free merges holes | analysis + coalescing | Ex 9, Ex 10 |
We visualise the shelf-of-holes idea once so every later example can lean on it:

Ex 1 — Exact fit (Cell C1)
Step 1. List holes that satisfy : B=250, C=400. Why this step? Best-fit only ever chooses among holes that actually fit. A=100 is disqualified immediately ().
Step 2. Pick the smallest qualifying hole. Between 250 and 400 the smallest is B=250. Why this step? "Best-fit = tightest fit" means minimum ; here , the tightest possible.
Step 3. Compute leftover: . Why this step? The leftover formula tells us the shard size. Zero leftover means the hole is fully consumed and is removed from the free list — not left as a 0-size hole.
Result: B disappears entirely. Free list becomes A=100, C=400.
Verify: leftover ; remaining free total ; original free was ; we allocated 250, so . ✓
Ex 2 — The tie-break (Cell C2)
Step 1. Qualifying holes (): A=300, B=200, C=300. Smallest is B=200. Why this step? Wait — B=200 is smaller than both 300s and still . So there is no tie for best-fit here; B wins outright.
Step 2. But suppose instead the request were P=250. Now qualifying holes are A=300, C=300 (B=200 fails). Both are size 300 — a genuine tie. Why this step? We engineered the actual tie so you see the rule.
Step 3. Tie-break: choose the hole at the lowest address (first in the list). So A, not C. Why this step? When sizes are equal, the standard convention is address order — it makes the algorithm deterministic and matches how the free list is traversed.
Result: For P=250, best-fit picks A, leftover ; C stays 300.
Verify: leftover ; free list becomes A=50, B=200, C=300, total ; original ; . ✓
Ex 3 — Failure despite plenty of free memory (Cells C3, C4)
Step 1. Total free . Tempting to say "yes". Why this step? To expose the trap: summing free memory is the wrong test.
Step 2. Apply the contiguity requirement: a request needs one single hole . Scan every hole: for all four. Why this step? Contiguous allocation cannot stitch two holes together. No matter which rule (first/best/worst), the set of qualifying holes is empty.
Step 3. Since no hole qualifies, allocation fails — for all three rules identically.
Result: P=50 FAILS even though 120 KB is free. This is pure external fragmentation.

Verify: so no single hole fits; total but that is irrelevant to a contiguous allocator. ✓
Ex 4 — Degenerate inputs (Cell C5)
Step 1 — (a) . Any hole (or none) satisfies . A well-behaved allocator treats a 0-size request as a no-op: allocate nothing, leave the free list untouched. Why this step? The condition is trivially true, so first-fit would "pick" the first hole and split it with leftover — i.e. no change. Cleanest to reject/ignore.
Step 2 — (b) empty free list. There are zero holes to scan. Every rule returns failure immediately. Why this step? All three rules begin by scanning the free list; an empty list gives an empty candidate set → fail. No special case needed.
Step 3 — (c) exact whole-hole request. One hole remains, say H=400, request P=400. Leftover , hole removed, free list becomes empty. Why this step? Same mechanic as Ex 1 but it empties memory. Confirms exact fit works at the boundary too.
Result: (a) no-op, (b) fail, (c) succeed with the free list emptied.
Verify: (a) leftover ⇒ free unchanged. (b) candidate count ⇒ fail. (c) ⇒ list empty. ✓
Ex 5 — Best-fit slivers the memory (Cell C6)
Step 1. P1=12. Qualifying (): 20, 15, 13. Tightest = 13, leftover . Why this step? Best-fit grabs the closest match, shaving off a 1 KB sliver — too small to ever reuse.
Step 2. P2=12. Remaining holes: 20, 15, (1). Qualifying: 20, 15. Tightest = 15, leftover . Why this step? Another tiny 3 KB dead shard is born.
Step 3. P3=12. Remaining: 20, (3), (1). Qualifying: 20 only. Leftover . Why this step? Even the big hole now yields an 8 KB shard.
Result: leftovers 1, 3, 8 — total KB free but no single hole ≥ 12. A fourth P4=12 would FAIL.
Verify: leftovers , , ; so a 4th request of 12 fails; sum . ✓
Ex 6 — Worst-fit starves a big request (Cell C7)
Step 1. P1=200. Largest hole = 600, leftover . Why this step? Worst-fit always chops the biggest hole, hoping the remainder stays useful.
Step 2. P2=200. Holes now 400, 500, 300. Largest = 500, leftover . Why this step? We just ate into the second-biggest hole.
Step 3. P3=450. Holes now 400, 300, 300. Largest = 400 — and no other hole . FAILS. Why this step? By spreading requests across the biggest holes, worst-fit demolished both large holes; the 450 has nowhere to land.
Result: the 450 FAILS — the exact starvation the parent warned about.
Verify: after two placements holes are ; ⇒ fail. ✓
Ex 7 — Same workload, three rules diverge (Cell C8)
Step 1 — First-fit. P1→B(500), lo 288. P2→E(600), lo 183. P3→B(288)→176. P4: holes {100,176,200,300,183}, max=300<426 → FAIL. Why this step? First-fit stops at the first fit each time — no size comparison — so it left no big enough hole for P4.
Step 2 — Best-fit. P1→D(300)lo88. P2→B(500)lo83. P3→C(200)lo88. P4→E(600)lo174. ALL SUCCEED. Why this step? Tightest fits preserved E=600 untouched until P4 needed it.
Step 3 — Worst-fit. P1→E(600)lo388. P2→B(500)lo83. P3→E(388)lo276. P4: max hole 300<426 → FAIL. Why this step? Worst-fit gnawed the big holes early; 426 starved.
Result: Best-fit places all four; first-fit and worst-fit strand P4.
Verify (best-fit leftovers): , , , , all ⇒ all succeed. ✓
Ex 8 — Word problem: the parking lot (Cell C9)
Step 1. Car 4 m, first-fit: scan 5≥4 → park in gap-1. Leftover . Why this step? First-fit takes the first gap that fits, in position order along the street.
Step 2. Van 7 m: scan 1(no), 8≥7 → gap-2. Leftover . Why this step? 1 m is too short; 8 m is the first that fits.
Step 3. Bus 11 m: scan 1,1,3,12≥11 → gap-4. Leftover . Why this step? First-fit reaches the 12 m gap and parks. The bus succeeds.
Result: all three park; leftovers are three useless 1 m slivers.
Verify: leftovers , , ; the bus's chosen gap ⇒ parks. ✓
Ex 9 — Exam twist: the 50% rule (Cell C10)
Step 1. The 50% rule (a classic analysis of first-fit) states: for allocated blocks, about blocks' worth of memory is lost to fragmentation. Why this step? It is an empirical/analytical result quoted in the parent's mistakes section — the exam expects the number .
Step 2. Compute lost block-equivalents. Why this step? Direct substitution.
Step 3. Fraction of free memory that is unusable: free blocks; but the rule counts fragmentation relative to allocated. A common exam form: if memory allocated free blocks and are fragmentation-bound within the free/hole structure, the wasted fraction . Why this step? Shows how to convert the count into a percentage the exam wants.
Result: blocks lost; of total memory affected.
Verify: ; ✓
Ex 10 — Exam twist: a free() coalesces holes (Cell C10)
Step 1. Freeing the 60 block makes it a hole. Now address order is: [hole 40][hole 60][hole 30][used 50][hole 20]. Why this step? A free() turns an allocated block back into a hole — but adjacency matters next.
Step 2. Coalescing: adjacent holes merge. The 40 and the newly-freed 60 are neighbours ⇒ merge to 100. The 30 sits after them but is separated from 100? Check adjacency: order is 40,60,30 all contiguous in address (no used block between the first three) ⇒ they merge into . Why this step? Compaction and Free List Management rely on merging neighbours so holes don't stay artificially fragmented. Only address-adjacent holes merge.
Step 3. New free list: [hole 130][used 50][hole 20]. Request 120: is any hole ? Yes, 130. SUCCEEDS, leftover . Why this step? Coalescing converted three small holes into one big enough hole — the request that failed before now fits.
Result: free list after coalescing = 130, 20; the 120 request succeeds with leftover 10.
Verify: merged hole ; leftover ; the un-merged max so coalescing was essential. ✓
Active Recall
What is the outcome when a request exactly equals the chosen hole size?
Best-fit tie-break rule when two holes are equally tight?
Can a 50 KB request fail when four 30 KB holes (120 KB total) are free?
What does a first-fit allocator do with a size-0 request?
Why does worst-fit starve large future requests?
What must happen to address-adjacent holes when a block is freed?
The 50% rule predicts how much loss for N allocated blocks?
Connections
- Paging — removes contiguity so Ex 3's failure never happens.
- Compaction — slides blocks to merge scattered holes (fixes Ex 3, Ex 5).
- Free List Management — the coalescing of Ex 10 lives here.
- Fragmentation — the sliver accumulation of Ex 5 quantified.
- Buddy System — an alternative allocator with power-of-two rounding.
- Segmentation · Virtual Memory — build on these placement ideas.