If you are taking our free Linux kernel development course, you already know that a kernel module cannot simply call malloc() the way user-space programs do. Instead, the kernel gives us kmalloc(), a fast, general-purpose allocator that sits on top of a clever memory-management layer called the slab allocator. In this lecture, we break down exactly what happens inside the kernel every time a driver asks for a small chunk of memory, and why understanding this matters for anyone learning free Linux device drivers and embedded systems development.
This lecture is fully updated for current kernels. Older tutorials online still describe the three-allocator world of SLAB, SLOB, and SLUB — that world no longer exists on a modern kernel, and we will explain exactly what changed and why it matters to you as a driver author.
Prerequisites
- Basic C programming knowledge (pointers, structures)
- A working Linux VM (any recent Ubuntu/Debian/Fedora works) with kernel headers installed
- Comfort writing and loading a “Hello World” kernel module (covered in our earlier free Linux kernel development course lectures)
- Root/sudo access on your test VM — never test kernel modules on a production machine
Why the Page Allocator Alone Is Not Enough
The lowest-level memory manager in the Linux kernel is the page allocator (the buddy system). It hands out memory in whole pages — typically 4 KB on x86_64. That is fine if a driver genuinely needs 4 KB or more. But most kernel data structures are tiny: a network packet descriptor, an inode, a small context structure of maybe 64 or 128 bytes. If every one of these small requests grabbed a full 4 KB page, the wastage would be enormous, and worse, physical memory would fragment badly over time.
for 12 bytes
hands out 4096 bytes
page is wasted
This is the exact gap that the slab allocator was built to close. It sits between the page allocator and the rest of the kernel, and it is the machinery behind every kmalloc() call you will ever make in a device driver.
What Is the Slab Allocator?
The slab allocator borrows a small number of pages from the page allocator and then carves each page into many equal-sized “objects.” A cache dedicated to 64-byte objects, for example, packs as many 64-byte slots as will fit into a page and hands them out one at a time. When your driver frees an object, it does not go back to the page allocator — it simply returns to a free list inside that same cache, ready for instant reuse. This is what makes kmalloc()/kfree() so much faster than repeatedly asking the page allocator for fresh pages.
SLAB vs SLUB vs SLOB — Which One Does the Modern Kernel Actually Use?
This is where our free Linux kernel development course content needs to correct a lot of outdated material floating around online. Historically the kernel shipped with three different slab-layer implementations, and developers could pick one at build time:
| Allocator | Purpose | Current Status |
|---|---|---|
| SLOB | Tiny, simple, first-fit allocator for very memory-constrained embedded boards | Removed from the mainline kernel (Linux 6.4) |
| SLAB | The original 1990s-derived design with per-CPU, shared and per-node queues | Removed from the mainline kernel (Linux 6.8) |
| SLUB | Simplified, lock-light design using per-CPU active slabs | The only allocator left — sole default since Linux 2.6.23, now the sole implementation |
What this means practically: on any kernel you install today, CONFIG_SLUB is simply “the slab allocator,” full stop. You will still see the word slab used generically in documentation, tool names (slabtop, /proc/slabinfo), and driver comments — that terminology stuck around even though SLUB is the only engine running underneath.
How kmalloc() Chooses a Cache
The kernel pre-creates a family of general-purpose caches sized in roughly power-of-two steps. When your code calls kmalloc(size, flags), the slab layer rounds your request up to the nearest matching cache and serves the object from there. There are actually several parallel families of these caches, chosen based on the allocation flags you pass in:
| Cache Family | Example Names | When It Is Used |
|---|---|---|
| KMALLOC_NORMAL | kmalloc-8 … kmalloc-8k | Default, plain GFP_KERNEL allocations |
| KMALLOC_RECLAIM | kmalloc-rcl-8 … kmalloc-rcl-8k | Memory the kernel can reclaim under pressure, reducing fragmentation |
| KMALLOC_CGROUP | kmalloc-cg-8 … kmalloc-cg-8k | Allocations charged to a memory control group (containers) |
| KMALLOC_DMA | dma-kmalloc-8 … dma-kmalloc-8k | Buffers that must be reachable by older DMA-limited hardware |
The reclaimable and cgroup-aware families are relatively recent additions and did not exist in the older kernels many textbooks were written against — another reason it is worth learning this from an updated, current source rather than a book written for an older release.
Inspecting Slab Caches From the Command Line
You do not need to write any code to see these caches in action. Two commands give you a live view:
$ sudo vmstat -m | grep "^kmalloc"
$ cat /proc/slabinfo | grep "^kmalloc"
Both commands read the same underlying kernel data, just formatted differently. You will see a growing list of caches such as kmalloc-8, kmalloc-16, kmalloc-32, all the way up to kmalloc-8k, alongside the kmalloc-rcl-N and kmalloc-cg-N variants described above. We go much deeper into reading this output, plus the live slabtop tool, in Part 2 of this lecture.
A Minimal kmalloc() Kernel Module
Let’s put the theory into practice with a small, original demo module. It allocates a buffer, writes to it, and releases it — the same pattern you will use in almost every real driver you write in this free Linux device drivers course.
#include <linux/init.h>
#include <linux/module.h>
#include <linux/slab.h>
#define DEMO_BUF_SIZE 256
static char *demo_buf;
static int __init epath_slab_demo_init(void)
{
demo_buf = kzalloc(DEMO_BUF_SIZE, GFP_KERNEL);
if (!demo_buf) {
pr_err("epath_slab_demo: allocation failed\n");
return -ENOMEM;
}
snprintf(demo_buf, DEMO_BUF_SIZE, "EmbeddedPathashala slab demo buffer\n");
pr_info("epath_slab_demo: allocated %d bytes, content: %s",
DEMO_BUF_SIZE, demo_buf);
return 0;
}
static void __exit epath_slab_demo_exit(void)
{
kfree(demo_buf);
pr_info("epath_slab_demo: buffer released\n");
}
module_init(epath_slab_demo_init);
module_exit(epath_slab_demo_exit);
MODULE_LICENSE("GPL");
MODULE_DESCRIPTION("EmbeddedPathashala kmalloc/kzalloc demo");
Notice we used kzalloc() instead of kmalloc(). The only difference is that kzalloc() zeroes the memory before handing it to you — a small but important habit that avoids leaking stale kernel data to user space by accident. We chose GFP_KERNEL because this code path runs in process context, where it is safe for the allocator to sleep if it needs to reclaim memory.
Build and test it like any other module:
$ make
$ sudo insmod epath_slab_demo.ko
$ dmesg | tail
$ sudo rmmod epath_slab_demo
Real-World Use Cases
- Network drivers use kmalloc-family caches constantly for socket buffer metadata and small protocol headers.
- Character and platform drivers allocate their private context/state structure with a single
kzalloc()call at probe time. - Filesystem code leans on the slab layer for inodes, dentries, and buffer heads — usually through dedicated
kmem_cacheobjects rather than generic kmalloc-N caches.
Common Mistakes and Troubleshooting Tips
| Mistake | Why It Hurts | Fix |
|---|---|---|
Forgetting kfree() |
Slow kernel memory leak, eventually OOM | Always pair every allocation with a matching free on every exit path |
Using GFP_KERNEL in interrupt context |
Can sleep where sleeping is not allowed — kernel warning or crash | Use GFP_ATOMIC inside interrupt handlers or spinlocks |
| Not checking the return value | A NULL pointer dereference on allocation failure | Always check for NULL before using the returned pointer |
Best Practices
- Prefer
kzalloc()overkmalloc()unless you have a measured performance reason not to zero the buffer. - Keep frequently accessed (“hot”) structure members grouped together near the top of your struct so they land on the same cache line.
- For a structure you allocate and free very often in a hot path, consider a dedicated
kmem_cache_create()cache instead of generic kmalloc.
Performance Considerations
SLUB keeps a separate “active slab” per CPU so that most allocations and frees never need a lock at all — they use a lockless compare-and-swap operation instead. This is why kernel allocation is dramatically faster than a typical user-space allocator on multi-core systems: contention between CPUs is designed out of the fast path from the start.
Security Considerations
Because SLUB stores its free-object pointer inside the freed object itself, corrupting a freed object (a classic heap overflow bug) can corrupt the allocator’s internal bookkeeping. Modern kernels defend against this with hardened usercopy checks, freelist pointer randomization, and optional debugging modes such as slub_debug=FZP for red-zoning and poisoning during development. If you are building drivers that handle untrusted input, always validate buffer lengths before copying into a kmalloc’d buffer.
Summary / Key Takeaways
- The slab allocator exists to avoid the massive waste of handing out full pages for tiny allocations.
- SLOB and SLAB have both been removed from the kernel; SLUB is the only slab allocator today.
kmalloc()automatically routes your request to the right size-class cache, including reclaimable, cgroup-aware, and DMA-capable variants.- Always pair allocation with a matching free, pick the right GFP flag for your context, and check for
NULL.
Conclusion
Understanding kmalloc() and the slab allocator is one of those foundational topics that pays off across every driver you will ever write. It explains why kernel memory allocation is so fast, why you should reach for kzalloc() by default, and why the flags you pass actually matter. In Part 2 of this free Linux kernel development course lecture, we go hands-on with slabtop, /proc/slabinfo, and a more complete kernel module that exercises kzalloc(), krealloc(), and kfree() together.
Frequently Asked Questions
No. SLAB was deprecated in Linux 6.5 and fully removed in Linux 6.8. Any kernel you build or install today uses SLUB exclusively.
kzalloc() does exactly what kmalloc() does, then zeroes the returned memory before handing it back to you.
Because the page allocator only hands out memory in whole pages (commonly 4 KB), a 12-byte request would waste almost the entire page. The slab allocator packs many small objects into a single page instead.
It is a reclaimable variant of the standard kmalloc-N caches. Memory in these caches can be reclaimed by the kernel under memory pressure, which helps reduce long-term fragmentation.
Use GFP_KERNEL in normal process context where sleeping is allowed. Use GFP_ATOMIC inside interrupt handlers, spinlocks, or any code path where the allocator must not sleep.
Yes, as long as you are comfortable with basic C and have already followed our earlier lectures on writing and loading a simple kernel module.
Set up a disposable Ubuntu virtual machine, install the matching kernel headers, and build the sample module shown above — never test kernel modules on production hardware.
Explore more free lectures on Linux kernel internals, device drivers, and embedded systems at EmbeddedPathashala.
