No best answer exists โ the request stream is the programmerโs whim, and any policy can be ambushed by the wrong workload. So the book does what engineers do: lay out the basic strategies, price them, and let the workload decide.
17.3 Basic Strategies
Best fit best fit Free-list strategy: search the whole list and return the SMALLEST chunk that satisfies the request โ minimizes leftover waste but pays for the exhaustive search and tends to leave tiny slivers. defined in ch. 17 โ open in glossary : search the whole list for candidates (chunks โฅ the request) and return the smallest โ closest to what was asked, least waste per grant. Cost: an exhaustive search, and a trail of tiny slivers. Worst fit worst fit Free-list strategy: return the LARGEST chunk, hoping to keep leftovers usefully big โ studies show it performs badly, with excess fragmentation and full-search overheads. defined in ch. 17 โ open in glossary inverts it: take the largest chunk, hoping leftovers stay usefully big. Also a full search โ and most studies show it simply performs badly. First fit first fit Free-list strategy: return the first chunk big enough โ fast (no exhaustive search) but can pollute the list's start with small splinters; address-ordered lists ease coalescing. defined in ch. 17 โ open in glossary grabs the first chunk big enough: no exhaustive search, but the front of the list silts up with splinters (address-based ordering helps, and eases coalescing too). Next fit next fit First fit plus a roving pointer: resume searching where the last search ended, spreading splinters through the list instead of piling them at the front. defined in ch. 17 โ open in glossary adds a roving pointer that resumes where the last search ended โ first-fit speed, splinters spread evenly.
amber outline = visited last search ยท green = chosen ยท sizes in bytes (headers ignored, as in the book's examples)
The book's outcomes: best fit โ 10 โ 30 โ 5 (searched all 3, chose 20, left a classic tiny sliver). Worst fit โ 10 โ 15 โ 20 (chose 30). First fit โ the same list as worst here, but it stopped searching after 2 nodes โ that cheapness is its whole argument. Reset and try a run of small requests under first fit to watch the front of the list silt up; then try next fit and watch the rover spread the damage.
17.4 Other Approaches
Segregated lists. If an application hammers one (or a few) sizes, give that size its own dedicated list segregated list Keeping a dedicated free list for a popular request size: near-zero fragmentation and O(1) alloc/free for that size, with the open question of how much memory to dedicate to it versus the general pool. defined in ch. 17 โ open in glossary : no search, no splitting, near-zero fragmentation for that size โ and a new headache (how much memory does the special pool get?). The definitive answer is Jeff Bonwickโs slab allocator slab allocator Bonwick's kernel allocator (Solaris): boot-time object caches โ segregated lists for hot kernel objects (locks, inodes) โ fed page-multiple slabs by a general allocator, with freed objects kept PRE-INITIALIZED to skip costly init/destroy cycles. defined in ch. 17 โ open in glossary (built for the Solaris kernel): at boot, create object caches for hot kernel objects (locks, file-system inodesโฆ); each cache is a segregated list of one size, and it trades memory with a general allocator dynamically โ requesting page-multiple slabs when low, returning them when the objectsโ reference counts all hit zero. One more trick: freed objects are kept in their initialized state, dodging the (measurably costly) init/destroy cycle on every reuse.
Aside: Great Engineers Are Really Great
Engineers like Bonwick (the slab allocator, then ZFS) are the heart of Silicon Valley. Behind almost any great product is a person โ or a small group โ way above average in talent and dedication. As the saying goes: someone exceptional isnโt a little better than someone pretty good; theyโre 100ร better. Work hard and you might become such a person. Failing that, work with one; youโll learn more in a day than most learn in a month. Failing that, feel sad.Buddy allocation. Since coalescing is what keeps a heap healthy, the binary buddy allocator buddy allocation Treat free memory as one 2^N space; recursively halve to the smallest sufficient power-of-two block (internal fragmentation is the tax). A freed block's buddy โ its address differs by exactly one bit โ is checked and merged, recursively, making coalescing trivial. defined in ch. 17 โ open in glossary designs everything around making it trivial:
1A 7KB request arrives
Free memory is conceptually ONE space of size 2^N โ here 64KB. The search for free space will recursively divide it by two until it finds the smallest block that still fits 7KB.
Other ideas. Plain lists donโt scale โ advanced allocators reach for balanced binary trees, splay trees, or partially-ordered trees to cut search costs. And the multiprocessor era bred allocators built for concurrency: Hoard, and Evansโs jemalloc (still inside FreeBSD, Firefox, and Facebookโs stack). For the real world in one dive, read how glibcโs malloc works.
17.5 Summary
Rudimentary allocators live everywhere: linked into every C program, and inside the OS managing its own structures. The recipe is now yours: splitting and coalescing over an embedded free list, headers to remember sizes, a fit policy chosen with the workload in mind, and โ when the workload cooperates โ segregated pools or buddy trees to make the common case fast. Building one allocator that is fast, space- efficient, and scalable for arbitrary workloads remains an open challenge. The next chapter takes the other exit: make every unit the same size, and watch the whole problem dissolve.
Homework: malloc.py
Drive a simulated allocator: predict alloc/free results and free-list states under BEST / WORST / FIRST (-p) with different list orderings (-l ADDRSORT / SIZESORT+ / SIZESORT-), then crank -n to 1000 and compare runs with and without coalescing (-C) โ watch what happens to large requests over time, and craft request streams (-A) that shatter the free space on purpose. Get it at ostep-homework.Check yourself
1.Free list: 10 โ 30 โ 20. Request: 15. What does each strategy leave behind?
2.First fit is fast but has a known disease, and a known palliative. Name both.
3.The slab allocator keeps segregated per-size caches for hot kernel objects. What TWO tricks make it more than a plain segregated list?
4.Why is coalescing nearly free in a binary buddy allocator โ and what's the tax it pays for that?
5.The chapter refuses to crown a best strategy. What's the fundamental reason?