A network packet arrives while the CPU is executing an interrupt handler. The kernel needs a small object to record the event.
In ordinary process context, an allocation can wait while the operating system searches for memory. An interrupt handler cannot simply block and let the scheduler resume it later. The allocation must succeed immediately from memory available to that context, or the handler needs a fallback such as dropping, deferring, or reusing work.
This is one reason kernel allocation needs more than a malloc() equivalent.
The kernel allocates objects ranging from tiny list nodes to large I/O buffers. Some callers may sleep; others may not. Some need physically adjacent memory; others need only a continuous virtual range. Device hardware can impose address restrictions, and failure in a critical path can prevent the system from freeing memory or completing I/O.
Kernel allocation is not only about size. It is also about context, physical layout, lifetime, locality, and forward progress.
Linux handles these requirements with several cooperating allocators rather than one universal function.
malloc()malloc() is a user-space library facility. It manages regions inside one process and can request more address space from the kernel.
The kernel sits below that interface. It must manage the physical memory and kernel address space from which user-space allocators ultimately obtain their regions. Calling a user-space allocator would reverse the dependency.
Kernel allocation also has different operational requirements:
Linux therefore provides allocation APIs that state more than a byte count. A request often includes flags describing whether the caller may sleep, which memory is eligible, and how hard the allocator may try.
A useful mental model has three main layers:
The page allocator manages physical memory in page-sized blocks.
The slab allocator takes groups of pages and divides them into reusable kernel objects.
The kmalloc() family provides general byte-sized allocations, commonly using slab size classes for small objects.
The vmalloc() family builds a continuous kernel virtual range from physical pages that do not need to be adjacent.
Specialized pools and subsystem allocators sit alongside these layers when the general-purpose path cannot meet latency, hardware, or forward-progress requirements.
The page allocator does not normally track RAM one byte at a time. It divides usable physical memory into fixed-size page frames.
Many systems use a 4 KiB base page size, although the size is architecture-dependent. With 4 KiB pages:
The kernel represents and tracks these physical frames with metadata. A page-frame number, or PFN, identifies a frame's position in physical memory.
Small kernel objects should not each consume a complete page. The object allocator subdivides pages for them. Large or layout-sensitive callers can request pages directly.
This chapter uses pages only as fixed-size physical allocation units. The mechanisms that translate general process addresses are not needed to understand the allocator hierarchy.
The following Linux APIs serve different needs:
| Need | Common API | Result |
|---|---|---|
| Small or moderate byte-sized object | kmalloc() or kzalloc() | Virtually and physically contiguous |
| Array with checked multiplication | kmalloc_array() or kcalloc() | kmalloc-style allocation |
| Many objects of one type | kmem_cache_alloc() | Object from a dedicated slab cache |
| One or more physical pages | alloc_pages() | Power-of-two number of contiguous pages |
| Large continuous kernel address range | vmalloc() or vzalloc() | Virtually contiguous, not necessarily physically contiguous |
Prefer kmalloc, accept virtual fallback | kvmalloc() or kvzalloc() | Physical layout depends on the successful path |
| Guaranteed reserve for critical progress | Memory pool API | Preallocated elements available under pressure |
The correct choice starts with the caller's actual requirements:
Choosing an overly strict API reduces the allocator's options and can make otherwise avoidable failures more likely.
kmalloc() Familykmalloc() is the normal general-purpose interface for small kernel objects:
It returns a kernel virtual address whose underlying allocation is physically contiguous. The pointer is suitably aligned according to the kernel's allocation guarantees.
The bytes are not initialized. kzalloc() requests the same kind of allocation and fills it with zeros:
Release either allocation with:
As with user-space allocation, kfree(NULL) is harmless. Double frees, freeing an interior pointer, and using an object after kfree() are invalid.
For arrays, use helpers that check multiplication:
Open-coding:
can allocate too few bytes if the multiplication overflows. kmalloc_array() performs checked multiplication without zeroing; kcalloc() also zeros the result.
General kmalloc() requests are commonly served from size-based slab caches.
An illustrative set of buckets might include:
The exact classes depend on the architecture and kernel configuration.
A 126-byte request can use a 128-byte bucket. The small difference is internal fragmentation:
Rounding makes allocation fast because the kernel can reuse an already prepared object of the appropriate class rather than search arbitrary free extents for every small request.
Larger kmalloc() requests can require a group of physically contiguous pages. As the requested order grows, success becomes more sensitive to physical fragmentation. It is good practice to use kmalloc() primarily for objects smaller than a page unless physical contiguity or another API contract specifically requires it.
The second argument to many Linux allocation functions is a set of GFP flags. GFP stands for “get free pages,” reflecting the physical page allocator below the higher-level APIs.
The flags answer questions such as:
The flags are part of correctness, not a performance hint to choose casually.
GFP_KERNELGFP_KERNEL is the normal choice for kernel data structures allocated from sleepable process context:
The allocator may perform substantial work and may put the current task to sleep while memory becomes available. The caller must not hold a lock or execute in a context that forbids sleeping.
GFP_NOWAITGFP_NOWAIT prevents the allocation from sleeping. It cannot perform direct reclaim that would block the caller.
This restriction makes failure more likely under pressure. The calling code needs a real fallback:
GFP_ATOMICGFP_ATOMIC also does not sleep and may use emergency reserves. It is appropriate only when using those reserves is justified because system progress depends on the allocation.
GFP_ATOMIC does not guarantee success. It is not simply a “faster GFP_KERNEL” and should not be used to hide a design that allocates unpredictably in a critical path.
The kernel has flags that alter retry effort, zero memory, restrict eligible zones, or avoid certain reclaim paths. Examples include __GFP_ZERO, __GFP_NORETRY, and __GFP_RETRY_MAYFAIL.
__GFP_NOFAIL expresses that an allocation must not fail and can retry indefinitely. It is reserved for exceptional cases where no valid recovery exists; using it for large or routine requests can stall the system.
Subsystem code may need to prevent reclaim from recursively entering filesystem or I/O paths while related locks are held. Such constraints should follow that subsystem's established allocation scopes and patterns rather than adding flags by guesswork.
If an allocation may sleep, the kernel can suspend the current task and run something else while it tries to make progress.
Sleeping is allowed in ordinary process context when the caller holds no non-sleepable locks. It is forbidden in contexts such as:
An interrupt handler is not an ordinary schedulable task waiting for a return value. Blocking it would violate execution and locking rules.
The decision must be based on the complete call path. A helper function may look harmless but still be called while a spinlock is held. Passing GFP_KERNEL in that path can trigger a “sleeping function called from invalid context” warning or deadlock.
The safest design is often to allocate before entering the atomic section, maintain a preallocated pool, or defer work to a sleepable context.
The Linux physical page allocator uses a buddy system to manage free blocks whose sizes are powers of two.
An order describes the number of contiguous pages:
With 4 KiB pages:
| Order | Pages | Size |
|---|---|---|
| 0 | 1 | 4 KiB |
| 1 | 2 | 8 KiB |
| 2 | 4 | 16 KiB |
| 3 | 8 | 32 KiB |
| 4 | 16 | 64 KiB |
The allocator maintains collections of free blocks at each supported order. An order-2 request needs four physically adjacent pages aligned as an order-2 block.
The buddy design makes splitting and merging predictable. Every block has one same-sized partner—its buddy—with which it can combine into the next order.
Kernel code can request an order directly from the page allocator:
An order-2 result represents four physically contiguous pages. The return value identifies the first page through kernel page metadata; it is not the same interface as a general byte-sized kmalloc() result.
Release the block with the same order:
The allocator needs the original order to return the block to the correct free list and attempt buddy merging. Passing the wrong order corrupts physical-memory accounting.
Direct page allocation is appropriate when the caller works in page units or needs a particular physical layout. For an ordinary small structure, the slab and kmalloc() layers provide better space efficiency.
Suppose the allocator needs an order-2 block but only has a free order-4 block.
An order-4 block contains 16 pages:
Split it into two order-3 buddies:
Split one order-3 block into two order-2 buddies:
Allocate one four-page block:
Only one path is split. The unused buddy at each level remains available in its corresponding free list.
This recursive halving finds the smallest power-of-two block that satisfies the request while preserving the other halves for future allocations.
Buddy blocks are aligned to their size. This structure lets the allocator calculate the matching block instead of searching all free memory.
If pfn is the first page-frame number of an order-N block, its buddy begins at:
The bit for that order distinguishes the lower and upper halves of their common parent.
For an order-2 block:
The buddy begins four pages away within the aligned eight-page parent.
This arithmetic is one reason buddy allocation is efficient: the allocator can locate the only possible merge partner directly.
When an order-2 block is freed, the allocator checks its order-2 buddy.
If the buddy is also free, remove both order-2 blocks from their free list and combine them into a single order-3 free block.
The new order-3 block now has its own buddy. If that buddy is also free, the two order-3 blocks merge into one order-4 block, and merging continues upward.
Merging stops when:
Two adjacent free blocks cannot merge unless they are same-order buddies. The power-of-two alignment rule preserves a unique hierarchy and keeps merging simple.
Loading simulation...
The buddy system makes coalescing fast, but power-of-two blocks create internal fragmentation.
If a caller needs at least five contiguous pages, the next available order is order 3:
Some APIs can return unused tail pages separately, but a raw order allocation is a power-of-two block.
High-order allocations are also vulnerable to external fragmentation. A zone can contain hundreds of free order-0 pages but no eight-page aligned run for an order-3 request.
This is why an unnecessarily large physically contiguous request is fragile on a long-running system. The kernel may try reclaim or compaction when the context allows, but callers should avoid demanding high-order physical contiguity when they need only a large virtual buffer.
Taking a global zone lock for every single-page allocation would scale poorly across many CPU cores.
Linux keeps frequently used free pages in per-CPU pagesets. A common single-page allocation can often be served from local CPU state:
A CPU-local request goes to the per-CPU pageset first, and only on a miss or low supply does it reach the global buddy free areas.
Pages move between per-CPU and global structures in batches. Batching reduces lock traffic and cache-line contention.
This creates temporary distribution. One CPU can hold locally free pages while another needs to refill from the global allocator. Thresholds keep the caches bounded and return excess pages.
The page allocator therefore has a fast local path and a broader buddy path, much like object allocators have local caches backed by shared arenas.
Not every physical page is equally usable for every request.
Linux divides physical memory into zones representing addressability and usage constraints. Depending on the architecture, these can include normal kernel-accessible memory and lower-address ranges needed by devices with limited addressing capabilities.
The allocation flags help determine which zones are eligible and the fallback order between them.
Using a scarce restricted zone for an ordinary object can starve a device that has no alternative. The allocator protects some lower zones and reserves to preserve system progress.
Most kernel code should use the normal API and flags appropriate to its context. Driver code should use the DMA mapping interfaces instead of assuming that a particular GFP zone flag alone satisfies every device requirement.
On systems with multiple memory nodes, locality adds another placement preference. The allocator may prefer memory near the requesting CPU and fall back according to the request's policy. That detail does not change the core page, slab, and context model used here.
The buddy allocator is efficient for pages, but a kernel contains enormous numbers of smaller objects:
Giving each object a whole page would waste most of memory. Repeatedly carving arbitrary byte ranges would add search and metadata overhead.
A slab allocator creates caches for objects of a particular type or size.
A slab is backed by one or more pages obtained from the page allocator. It is divided into same-sized object slots.
The cache tracks slabs that are:
Allocation prefers an available object from a partial or CPU-local slab. Freeing returns the slot to its cache. When an entire slab becomes empty, the allocator can retain it for reuse or return its backing pages.
Fixed object sizes provide several benefits.
The allocator can take one slot from a free-object list instead of searching variable-sized holes.
A freed network descriptor is likely to become another network descriptor. Reusing the same memory avoids repeatedly constructing general allocator metadata.
The cache can place each object at an alignment suitable for the type and CPU.
All slots in one cache have the same size. There is no external fragmentation between differently sized objects inside that slab.
Internal fragmentation remains possible. An object size may be rounded for alignment, and a partially occupied slab contains unused slots that cannot serve a different cache.
The allocator can apply red zones, poisoning, allocation tracking, and other checks consistently to objects from a cache.
These features cost memory and CPU time, so production configurations choose different tradeoffs from debugging configurations.
A subsystem allocating many instances of one structure can create a dedicated cache:
Allocate and release objects with:
The cache must outlive all objects allocated from it. Destroying a cache while live objects remain is a lifecycle bug.
A custom cache is worthwhile when object frequency, construction, alignment, debugging, or user-copy rules justify it. For occasional ordinary structures, kmalloc() or kzalloc() is simpler.
Linux has multiple slab allocator implementations and configuration choices. SLUB is common, while slab allocator remains the generic name for the object-caching design.
kmalloc() on Top of Slab CachesThe general kmalloc() interface commonly uses predefined slab caches for size classes:
A kmalloc request is rounded up to a size class, served from the kmalloc-128 cache, and returns a 128-byte slot.
This connects the allocator layers:
kmalloc(126, flags) is called.The page allocator handles physical blocks. The slab layer subdivides those blocks into objects. kmalloc() selects a general-purpose object size.
An allocation failure can therefore originate at several layers: no free object, inability to grow the cache, page-allocation failure, unsuitable zone, disallowed reclaim, or an impossible contiguity requirement.
Slab allocators also keep fast per-CPU state.
The common path can allocate an object from the current CPU's active slab without taking a global lock. Frees can return objects locally and transfer batches to shared structures later.
Each CPU serves most allocations from its own objects without touching the shared cache. The shared structures are reached only when a CPU's local supply runs out.
This improves throughput and avoids cache-line bouncing between cores.
It also means free objects can be distributed across CPUs and slabs. A cache may retain more memory than the count of currently live objects suggests because partially occupied slabs and local free lists are not immediately returned to the page allocator.
Concurrency optimizations exchange some memory efficiency for lower synchronization cost.
Loading simulation...
vmalloc() for Large Virtual Rangesvmalloc(size) creates a contiguous range in kernel virtual address space backed by physical pages that need not be adjacent:
The four virtual pages are consecutive and the physical frames behind them are not. Code reading through the range sees one contiguous buffer, while a device performing DMA would not.
The caller can index the result as one continuous buffer. Physical contiguity is absent.
This makes vmalloc() suitable for large software-only buffers when a high-order physical allocation would be fragile.
The flexibility has costs:
kmalloc() operations.vfree() has context restrictions and should not be treated like an arbitrary atomic-context free.vzalloc() is the zero-initializing variant. Release the range with vfree().
vmalloc() memory is not a substitute for device-specific DMA allocation. A device cannot infer a usable contiguous bus address from the kernel virtual pointer.
kvmalloc() as a Flexible Choicekvmalloc(size, flags) first attempts a kmalloc()-style physically contiguous allocation. If that fails, it can fall back to vmalloc()-style noncontiguous physical backing.
The caller gets working memory either way, but not the same guarantees. Code that needs physical contiguity cannot use this.
The caller must not depend on physical contiguity because the successful path can vary.
Free the result with:
The zeroing variant is kvzalloc().
kvmalloc() is useful for a potentially large software buffer whose callers need one continuous virtual pointer but do not care about its physical layout. Its supported flags and contexts are more restricted than arbitrary kmalloc() use, so callers must follow the API contract rather than mechanically replacing every large allocation.
A device performs direct memory access using addresses and rules that can differ from ordinary CPU access.
Even when kmalloc() provides physically contiguous memory, converting its kernel pointer into a device address is not a portable DMA strategy. The system may have:
Drivers should use interfaces such as:
These APIs return or establish an address suitable for the particular device and platform.
The distinction is:
Those values can be related without being numerically identical.
Some kernel operations need memory in order to complete the work that will free memory.
Imagine a storage path that must allocate a small request object before it can write dirty data and release cached pages. If that allocation waits for memory that only the same I/O path can free, the system can deadlock.
A memory pool reserves a minimum number of elements in advance:
When the normal allocation succeeds, the normal allocator is used. When it fails, an element is taken from the reserved pool.
Returned elements refill the reserve.
The pool is not extra memory created during failure. Its guarantee comes from preallocation performed when memory was available.
Memory pools are intended for bounded, critical paths where a known number of in-flight elements preserves progress. They are not a general way to make every allocation infallible. If callers consume the reserve without eventually returning elements, the pool can still be exhausted or force waiters to block.
Sizing requires understanding the maximum dependency chain, not choosing an arbitrary large reserve.
Kernel allocation APIs commonly return NULL on failure. Correct code must define what happens next.
A simple initialization path can unwind:
More complex code should release resources in reverse acquisition order. Kernel code often uses goto labels to keep this cleanup centralized:
An atomic path needs a bounded fallback. Depending on the subsystem, it might:
Retrying the same non-sleeping request in a tight loop does not create memory and can lock up the CPU.
A sleepable allocation can ask the kernel to work harder than an atomic allocation.
Depending on flags and system state, the allocator may:
These actions can make GFP_KERNEL latency much larger than its fast-path latency. Most allocations complete quickly, but code must not assume a strict upper bound unless it uses a preallocated design.
Retry modifiers express how aggressively the allocator should pursue success. They must match the caller's recovery options:
Using the strongest retry flag everywhere hides design errors and can turn a recoverable shortage into a system-wide stall.
User-space allocations are ultimately discarded when their process exits. Kernel objects can have independent lifetimes.
A network connection object may be referenced by:
Freeing it safely requires proving that no reference can use it afterward.
The allocator tracks whether a chunk is allocated; it does not understand subsystem ownership. Reference counts, locks, deferred-destruction mechanisms, and explicit state machines provide that higher-level lifetime control.
Likewise, losing the last pointer creates a kernel memory leak. The memory remains allocated until the subsystem recovers it or the machine reboots.
Lifecycle design should answer:
An invalid user-space free usually terminates one process. An invalid kernel free can corrupt allocator metadata shared by the complete kernel.
Common errors include:
kfree()These bugs can cause unrelated crashes much later. They can also become security vulnerabilities because corrupted function pointers, credentials, or object metadata execute in privileged context.
Zero allocation is useful when all-zero is a valid initial state:
It does not replace explicit initialization for fields whose valid state is nonzero or whose invariants require ordering.
Sensitive buffers should be cleared with kernel helpers designed not to have the clearing optimized away before release.
Linux provides optional tools that trade performance and memory for better diagnostics.
KASAN detects many out-of-bounds and use-after-free accesses.
KFENCE samples allocations to find memory errors with lower steady-state overhead than full instrumentation.
SLUB debugging can add red zones, poisoning, and consistency checks around slab objects.
kmemleak scans for potentially unreachable kernel allocations.
Allocator fault injection can force selected allocation failures, revealing cleanup paths that normal testing rarely executes.
A report at kfree() does not prove the bug occurred there. The allocator may be the first code to inspect metadata corrupted by an earlier overflow.
The full page and slab allocators are not available at the first instruction of kernel startup. They depend on metadata and structures that must themselves be initialized.
Linux uses an early-boot allocator, commonly called memblock, to track available and reserved physical ranges while the main allocators are being constructed.
The boot sequence conceptually looks like:
memblock tracks the available and reserved ranges.Some early allocations remain reserved permanently for kernel code and metadata. Others are released to the normal page allocator after initialization.
This bootstrap layer solves a general systems problem: an allocator needs memory for its own bookkeeping before it can manage memory normally.
Linux exposes the buddy allocator's free-block counts through:
A representative line looks like:
After the node and zone, columns represent order 0, order 1, order 2, and so on.
With 4 KiB pages:
To compute bytes represented by one column:
Many low-order blocks alongside zero high-order blocks indicate that free memory is physically fragmented for large contiguous requests.
/proc/buddyinfo is a snapshot of buddy free areas, not a complete memory-capacity report. Per-CPU caches, reserved memory, reclaimable objects, zone restrictions, and concurrent activity all affect whether a real request succeeds.
The kernel exposes slab-cache statistics through:
Access may be restricted because detailed kernel allocation information can be security-sensitive.
The interactive slabtop utility presents cache activity:
Typical cache names correspond to:
kmalloc size classesUseful fields include active objects, total objects, object size, and slabs. A cache can contain many free slots while retaining its backing slabs for reuse.
High slab use is not automatically a leak. It may represent a legitimate cache. Investigate whether object counts track workload, whether they decline after activity, and whether the subsystem has a shrink or teardown path.
vmalloc RegionsOn systems that expose it, inspect virtual kernel allocations with:
This interface is commonly restricted to privileged users.
Entries describe virtual ranges, sizes, callers, and mapping details. They represent kernel virtual allocations, not one physically contiguous RAM list.
The three diagnostic views answer different questions:
No single file explains all kernel memory use. The layer named by the failing allocation determines which view is most relevant.
For a normal, small kernel structure in sleepable context, start with:
Use kcalloc() or kmalloc_array() for arrays so multiplication is checked.
Use a dedicated slab cache when a subsystem creates many identical objects and needs type-specific alignment, debugging, or reuse behavior.
Use alloc_pages() when the caller truly needs page objects or a power-of-two physically contiguous run.
Use vmalloc() for a large software buffer that needs virtual but not physical contiguity. Use kvmalloc() when a physically contiguous fast path is welcome but not required.
Use the DMA API for device-accessible buffers.
Use a memory pool when a bounded reserve is necessary for forward progress under allocation failure.
Choose GFP flags from the execution context and reclaim constraints. The broadest safe context gives the allocator the best chance of success; unnecessary restrictions make memory harder to find.
Linux kernel memory allocation is layered. The buddy allocator manages power-of-two blocks of physical pages. Slab allocators divide groups of pages into reusable same-sized objects, and kmalloc() uses general size-class caches for ordinary byte-sized allocations.
Allocation context is part of correctness. GFP_KERNEL may sleep and reclaim memory, while non-sleeping allocations have fewer options and fail more readily. GFP_ATOMIC may use reserves but does not guarantee success. Critical paths need preallocation, memory pools, or bounded fallback behavior.
kmalloc() supplies physically contiguous storage and is best suited to smaller objects. vmalloc() supplies a contiguous kernel virtual range without requiring adjacent physical pages. kvmalloc() permits either layout, while device buffers should use the DMA API.
Buddy splitting and merging make page coalescing efficient, but high-order requests remain vulnerable to physical fragmentation. Slab and per-CPU caches improve speed and concurrency at the cost of retained memory and partially occupied slabs.
The central design rule is:
Choose the allocator from the caller's context and layout requirements, not from size alone.
5 quizzes