Unveiling Linux Slab Cache: How the Kernel Frees Memory Step‑by‑Step
This article walks through the Linux kernel's slab cache memory‑freeing path, explaining the kmem_cache_free API, validation steps, fast‑path and slow‑path reclamation, CPU‑local and NUMA‑node handling, and the final destruction of slab caches with detailed code examples.
In the previous article the author introduced the full allocation path of the Linux slab cache; this continuation focuses on how memory is released back to the slab cache once an object is no longer needed.
1. Kernel API for freeing objects
The kernel provides void kmem_cache_free(struct kmem_cache *s, void *x), where s is the slab cache the object belongs to and x is the virtual address of the object to be freed.
2. Validation before freeing
Before releasing the object, the kernel calls cache_from_obj to verify that the object really belongs to the specified slab cache. It then uses virt_to_head_page to locate the physical page that contains the object and finally invokes slab_free to return the object to the cache.
void kmem_cache_free(struct kmem_cache *s, void *x) {
// Ensure the object really belongs to the slab cache
s = cache_from_obj(s, x);
if (!s)
return;
// Return the object to the slab cache
slab_free(s, virt_to_head_page(x), x, NULL, 1, _RET_IP_);
}3. Memory‑release fast path
The fast path attempts to return the object to the CPU‑local slab cache. If the slab that holds the object is currently cached in kmem_cache_cpu->page, the kernel updates the per‑CPU freelist directly.
static __always_inline void slab_free(struct kmem_cache *s, struct page *page,
void *head, void *tail, int cnt,
unsigned long addr) {
if (slab_free_freelist_hook(s, &head, &tail))
do_slab_free(s, page, head, tail, cnt, addr);
}The core of the fast path is the do_slab_free function, which first obtains the correct per‑CPU cache structure, checks that the current CPU matches the one recorded in the slab (using a tid field), and then either inserts the object into the per‑CPU freelist or falls back to the slow path.
4. Memory‑release slow path
If the slab is not in the per‑CPU cache, the kernel follows a more complex slow path. It first clears the object's contents via free_debug_processing, then inserts the object back into its owning slab and updates the slab's page metadata (freelist, inuse, frozen). Depending on the slab's state, one of four scenarios is handled:
The slab is already in the per‑CPU partial list – no relocation is needed.
The slab was a full slab and became partial; it is added to the per‑CPU partial list.
The slab became empty; it is moved to the NUMA‑node partial list, respecting the min_partial limit.
The slab is empty and the node's partial list is full; the slab is released back to the buddy allocator.
Key helper functions include put_cpu_partial (which may drain the per‑CPU list to the node list), unfreeze_partials (which transfers slabs from per‑CPU to node lists), and discard_slab (which frees the underlying pages).
5. Slab cache destruction
When a slab cache is no longer needed, kmem_cache_destroy reduces the reference count, checks for remaining references, and then calls shutdown_cache. The shutdown process releases all per‑CPU and per‑node slabs, removes the cache's sysfs entries, and finally frees the core kmem_cache, kmem_cache_cpu, and kmem_cache_node structures.
void kmem_cache_destroy(struct kmem_cache *s) {
if (!s)
return;
get_online_cpus();
get_online_mems();
mutex_lock(&slab_mutex);
s->refcount--;
if (s->refcount)
goto out_unlock;
err = shutdown_memcg_caches(s);
if (!err)
err = shutdown_cache(s);
if (err)
pr_err("kmem_cache_destroy %s: Slab cache still has objects
", s->name);
out_unlock:
mutex_unlock(&slab_mutex);
put_online_mems();
put_online_cpus();
}The shutdown routine first calls flush_all to free per‑CPU slabs, then iterates over each NUMA node to free node‑local slabs, and finally removes the cache's sysfs directory.
6. Summary
The article completes the slab cache series by detailing the validation, fast‑path, and slow‑path release mechanisms, the handling of per‑CPU and NUMA‑node partial lists, and the complete teardown of a slab cache. Readers now have a full picture of how the Linux kernel manages slab‑based memory allocation and reclamation.
Signed-in readers can open the original source through BestHub's protected redirect.
This article has been distilled and summarized from source material, then republished for learning and reference. If you believe it infringes your rights, please contactand we will review it promptly.
Bin's Tech Cabin
Original articles dissecting source code and sharing personal tech insights. A modest space for serious discussion, free from noise and bureaucracy.
How this landed with the community
Was this worth your time?
0 Comments
Thoughtful readers leave field notes, pushback, and hard-won operational detail here.
