The vmalloc() Allocator: Why the Kernel Has a Second Memory Allocator for Physically Fragmented RAM

2026-08-20

You already know kmalloc(): it hands back a pointer to memory that is contiguous in both virtual and physical address space, carved from the buddy/slab allocators. But kmalloc(16 * 1024 * 1024, GFP_KERNEL) often fails on a long-running server even with gigabytes free. Why? Because the buddy allocator needs an unbroken run of order-12 pages (16MB), and after weeks of uptime, physical memory is Swiss cheese. This is where vmalloc() earns its keep.

What vmalloc actually does. It grabs N individual physical pages (order-0 allocations, which almost never fail), then patches together kernel page-table entries in a dedicated virtual address range (VMALLOC_START to VMALLOC_END, typically 32TB on x86-64) so the pages appear contiguous to your kernel code. The pointer you get back is a normal-looking kernel virtual address, but there is no linear offset from physical — virt_to_phys() is undefined behavior on it.

The costs you pay.

Real-world example. When you insmod a kernel module, the loader calls module_alloc(), which is vmalloc under the hood (in a special sub-range that keeps modules within ±2GB of the kernel text so call rel32 instructions can reach). A 400KB module = 100 order-0 pages stitched together. It doesn't matter that physical RAM is fragmented; the module still loads.

Rule of thumb. Use kmalloc up to about 8KB freely, up to 128KB with care, and switch to vmalloc (or kvmalloc, which tries kmalloc first and falls back automatically) anywhere above that — unless you need DMA or hot-path performance, in which case reserve at boot with alloc_pages(GFP_KERNEL, order) while memory is still un-fragmented.

The kernel's own filesystems demonstrate this: XFS uses kvmalloc for its extent buffers precisely because a 64KB allocation might succeed as kmalloc on a fresh boot and only need vmalloc after weeks of uptime.

See it in action: Check out Large Memory Management issues: Performance, Fragmentation, Movable objects and Huge Page overhead. by LinuxConfAu 2018 - Sydney, Australia to see this theory applied.
Key Takeaway: vmalloc() trades TLB pressure, DMA-incompatibility, and per-alloc metadata for the ability to satisfy large allocations from a fragmented physical memory pool that kmalloc() cannot.

All newsletters