How do SLUB and SLOB memory allocators handle memory fragmentation

How do SLUB and SLOB memory allocators handle memory fragmentation

Every time the Linux kernel needs a small chunk of memory — a task_struct, an inode, a network buffer — it doesn’t go begging the buddy allocator for a fresh page. That would be wasteful. Instead, it turns to one of the kernel’s slab-style allocators. I want to spend this article digging into two of them, SLUB and SLOB, and specifically how each one deals with the oldest enemy of any memory manager: fragmentation.

I’ve spent a fair amount of time reading kernel source and tracing allocator behavior on embedded boards, and one thing becomes obvious quickly — fragmentation isn’t a single problem. It’s two related but distinct problems, and SLUB and SLOB take almost opposite philosophies toward solving them.

Two Kinds of Fragmentation

Before comparing allocators, it helps to separate the two flavors of fragmentation that matter in kernel memory management.

Internal fragmentation happens when an allocator hands out a block bigger than what was requested. If I ask for 40 bytes and the allocator gives me a 64-byte slot because that’s the nearest size class, the leftover 24 bytes are wasted — they’re allocated but unusable by anyone else.

External fragmentation happens when free memory exists in total, but it’s scattered in pieces too small or too oddly placed to satisfy a request. You might have a full free page’s worth of memory technically available, split across a dozen partially-used slabs, and still fail to service a request that needs contiguous space.

Both SLUB and SLOB are trying to minimize the sum of these two costs, but they’re built for very different environments.

SLUB’s Approach: Structure Over Cleverness

SLUB (the “unqueued slab allocator”) is the default allocator on almost every mainstream Linux distribution and server kernel today. It replaced the original SLAB allocator specifically because SLAB’s per-CPU queuing and object tracking metadata scaled poorly on machines with many cores and large memory.

SLUB fights fragmentation with structure. Memory is divided into fixed-size object caches — kmalloc-32, kmalloc-64, kmalloc-96, and so on, jumping in fairly fine-grained steps. Each cache manages one or more slabs, which are just contiguous runs of pages divided evenly into object-sized slots.

A few design choices matter here:

  • Per-CPU partial lists. Each CPU keeps a small stash of partially-filled slabs. When a thread on that CPU needs an object, SLUB grabs it from the CPU’s own slab first, avoiding lock contention and keeping allocation patterns local, which in turn keeps slabs from spreading thin across the whole system.
  • Size classes minimize internal waste. Because size classes step up in small increments (not just powers of two beyond a point), a 40-byte object doesn’t get stuck in a 128-byte slot the way older allocators might force it to.
  • Slab consolidation. When a slab becomes completely empty, SLUB can return it to the buddy allocator, undoing external fragmentation at the page level. Partially-used slabs are prioritized for future allocations over freshly carved ones, so existing gaps fill in before new slabs get created.
  • Debugging and redzoning are compiled out in production, so the “clean” path is memory efficient by default; extra metadata used to exist per-object in SLAB, but SLUB pushes a lot of that bookkeeping into the page structure itself, cutting overhead.

The tradeoff SLUB makes is that it assumes you have enough RAM that a bit of internal fragmentation per object is an acceptable price for speed and simplicity. It targets throughput on multi-core servers over squeezing out the very last kilobyte.

SLOB’s Approach: Squeeze Every Byte

SLOB (“Simple List Of Blocks”) takes the opposite bet. It assumes you’re memory-starved — think routers, older feature phones, or tiny embedded Linux boards with a few megabytes of RAM — and that CPU cycles spent hunting for a good-fit block are cheaper than wasted bytes.

SLOB doesn’t use fixed size classes at all. Instead it manages memory as a linked list of free chunks, similar in spirit to a classic heap allocator like dlmalloc. When a request comes in, SLOB walks the free list using a first-fit (with some best-fit tuning) strategy, looking for a chunk that’s just big enough. If it finds one bigger than needed, it splits it, returning the front portion and keeping the remainder on the free list.

This gives SLOB excellent internal fragmentation numbers — it rarely wastes more than a few bytes per allocation, since it isn’t rounding up to a size class. But it pays for that in two other ways:

  • External fragmentation creeps in over time. As objects of different sizes are allocated and freed in essentially random order, the free list becomes a patchwork of odd-sized gaps. A large allocation request can fail to find a contiguous fit even when total free memory would easily cover it, forcing SLOB to request another page from the buddy allocator — which itself doesn’t shrink easily once carved up this way.
  • List traversal cost grows. Every allocation potentially means walking a linked list of arbitrary length. On a system doing thousands of allocations per second, this is a real cost, which is part of why SLOB never made sense for server-class hardware.

Side-by-Side Comparison

AspectSLUBSLOB
Fragmentation priorityBalances internal & externalMinimizes internal, tolerates external
Allocation strategyFixed size-class slabsLinked-list first/best fit
SpeedFast, per-CPU cachingSlower, list traversal
Best forServers, desktops, general-purposeTiny embedded / memory-constrained devices
Metadata overheadLow, page-embeddedVery low, minimal bookkeeping
Status in modern kernelDefaultDeprecated, removed in newer kernels

Worth noting: SLOB has actually been removed from the mainline kernel as of the 6.4 development cycle. Its niche has largely been absorbed by SLUB in a leaner configuration, plus improvements in the buddy allocator’s own compaction machinery. I’m covering it here because it’s still an excellent teaching example and it still ships in older LTS kernels that plenty of embedded products run today.

Real-World Behavior

On a Raspberry Pi Zero-class board running an old Buildroot image with SLOB, I’ve seen /proc/slabinfo-style metrics show fragmentation creep after long uptimes — services allocating and freeing buffers of varying sizes over days would eventually push the kernel to request more pages from the buddy allocator even though free -m showed plenty of “free” memory in aggregate. That’s classic external fragmentation.

On the flip side, watching slabtop on a busy Linux server running SLUB, you’ll typically see slab utilization sit comfortably high (80-90%+ objects used per slab) because the per-CPU partial-list logic actively tries to fill existing slabs before carving new ones.

Troubleshooting Fragmentation Symptoms

If you suspect an allocator-related fragmentation issue:

  1. Check /proc/slabinfo or slabtop for cache utilization ratios — low active_objs relative to num_objs on a given cache signals waste.
  2. Check /proc/buddyinfo to see how fragmented free memory is at the page level (lots of order-0 pages with few high-order blocks means the page allocator itself is fragmented).
  3. On memory-tight embedded targets still running SLOB, consider switching to SLUB with tighter min/max order tuning, since modern SLUB configurations can often match SLOB’s footprint without the list-walk overhead.
  4. Watch out for kmalloc size-class mismatches — requesting oddly sized buffers repeatedly (SLUB) can waste more than expected; consider using kmem_cache_create() for a custom exact-size cache in hot paths.

Best Practices

  • Don’t fight the allocator with manual pooling unless profiling shows a real problem — SLUB’s per-CPU caching already solves most contention issues.
  • For embedded work, measure actual RSS and fragmentation over realistic uptimes, not just boot-time numbers — SLOB’s weaknesses only show up after sustained mixed-size allocation patterns.
  • If you maintain an old kernel still using SLOB, plan a migration path to SLUB before your next LTS jump, since SLOB support is gone upstream.

Summary

SLUB and SLOB represent two honest, different answers to the same question — how do you hand out kernel memory efficiently when you can’t predict what will be requested next? SLUB bets on structure, per-CPU locality, and tolerating a little internal waste in exchange for speed and predictable behavior at scale. SLOB bets on tight packing and accepts that free space will get chopped into oddly shaped leftovers over time. For virtually every modern system, SLUB is the right and, at this point, the only mainline choice — but understanding SLOB’s design is still one of the best ways to actually understand what “fragmentation” means at the allocator level.

FAQs

Is SLOB still in the Linux kernel? No. SLOB was removed from mainline starting with kernel 6.4. Older LTS branches still carry it.

Which allocator is faster, SLUB or SLAB? SLUB is generally faster on modern multi-core hardware due to reduced locking and per-CPU partial lists, which is why it replaced SLAB as the default.

Does SLUB ever suffer from external fragmentation? Yes, at the page level, particularly under memory pressure with mixed high-order allocations, but it mitigates this far better than SLOB through slab consolidation and interaction with the buddy allocator’s compaction.

Can I choose the allocator at boot time? On kernels that still support it, you can select the slab allocator via a kernel config option (CONFIG_SLUB, CONFIG_SLOB where available) at build time; some distros also expose a boot parameter.

References

  • Linux kernel source: mm/slub.c, mm/slob.c (Linux kernel documentation tree)
  • Linux Kernel Documentation, “Short users guide for SLUB” — kernel.org/doc
  • Bonwick, J., “The Slab Allocator: An Object-Caching Kernel Memory Allocator” (original slab paper)
  • Linux Weekly News (LWN.net) articles on slab allocator history and SLOB removal
Total
0
Shares

Leave a Reply

Previous Post
What is the SLOB (Simple List Of Blocks) memory allocator in the Linux kernel

What is the SLOB (Simple List Of Blocks) memory allocator in the Linux kernel

Next Post
How does the Linux kernel ensure memory protection for kernel space

How does the Linux kernel ensure memory protection for kernel space

Related Posts