Memory Allocators

The kernel provides several memory allocation functions, each designed for different use cases. Choosing the right one is essential for correctness and performance.

kmalloc: General Purpose Allocator

The most common allocator, similar to user-space malloc():

#include <linux/slab.h>

void *ptr;

/* Allocate memory */
ptr = kmalloc(size, GFP_KERNEL);
if (!ptr)
    return -ENOMEM;

/* Use the memory */
/* ... */

/* Free when done */
kfree(ptr);

kmalloc Characteristics

  • Returns physically contiguous memory
  • Fast for small allocations (uses slab cache)
  • Maximum size typically ~128KB (depends on architecture)
  • Returns actual size >= requested (rounded to power of 2)

Common kmalloc Variants

/* kmalloc with zeroing */
ptr = kzalloc(size, GFP_KERNEL);  /* Zeroed memory */

/* kmalloc for arrays */
ptr = kmalloc_array(n, elem_size, GFP_KERNEL);  /* Overflow-safe */

/* kzalloc for arrays */
ptr = kcalloc(n, elem_size, GFP_KERNEL);  /* Zeroed array */

/* Reallocate */
new_ptr = krealloc(ptr, new_size, GFP_KERNEL);

/* Duplicate string */
new_str = kstrdup(str, GFP_KERNEL);
new_str = kstrndup(str, max_len, GFP_KERNEL);

/* Duplicate memory */
new_ptr = kmemdup(ptr, size, GFP_KERNEL);

Example: Basic Allocation

struct my_data {
    int id;
    char name[32];
    void *buffer;
};

static struct my_data *create_my_data(int id, const char *name)
{
    struct my_data *data;

    data = kzalloc(sizeof(*data), GFP_KERNEL);
    if (!data)
        return NULL;

    data->id = id;
    strscpy(data->name, name, sizeof(data->name));

    data->buffer = kmalloc(1024, GFP_KERNEL);
    if (!data->buffer) {
        kfree(data);
        return NULL;
    }

    return data;
}

static void destroy_my_data(struct my_data *data)
{
    if (!data)
        return;

    kfree(data->buffer);
    kfree(data);
}

vmalloc: Large Allocations

For allocations larger than what kmalloc can handle:

#include <linux/vmalloc.h>

void *ptr;

/* Allocate virtually contiguous memory */
ptr = vmalloc(large_size);
if (!ptr)
    return -ENOMEM;

/* Use the memory */
/* ... */

/* Free when done */
vfree(ptr);

vmalloc Characteristics

  • Memory is virtually contiguous, not physically
  • Can allocate much larger regions
  • Slower than kmalloc
  • Cannot be used for DMA (not physically contiguous)
  • Always sleeps (cannot use in atomic context)

vmalloc Variants

/* Zeroed vmalloc */
ptr = vzalloc(size);

/* With specific NUMA node */
ptr = vmalloc_node(size, node);
ptr = vzalloc_node(size, node);

/* For executable code */
ptr = __vmalloc(size, GFP_KERNEL);

kvmalloc: Flexible Allocator

Tries kmalloc first, falls back to vmalloc:

#include <linux/mm.h>

/* Best of both worlds */
ptr = kvmalloc(size, GFP_KERNEL);

/* With zeroing */
ptr = kvzalloc(size, GFP_KERNEL);

/* Array allocation */
ptr = kvmalloc_array(n, size, GFP_KERNEL);
ptr = kvcalloc(n, size, GFP_KERNEL);

/* Free (works for either) */
kvfree(ptr);

When to Use kvmalloc

  • Size might be small or large
  • Physical contiguity not required
  • Good default choice for flexible sizes

Page Allocator

For page-aligned allocations:

#include <linux/gfp.h>

/* Allocate 2^order pages */
struct page *page = alloc_pages(GFP_KERNEL, order);
if (!page)
    return -ENOMEM;

/* Get virtual address */
void *addr = page_address(page);

/* Free pages */
__free_pages(page, order);

/* Or simpler interface */
unsigned long addr = __get_free_pages(GFP_KERNEL, order);
free_pages(addr, order);

/* Single page */
unsigned long addr = __get_free_page(GFP_KERNEL);
free_page(addr);

/* Zeroed page */
unsigned long addr = get_zeroed_page(GFP_KERNEL);

Page Order

Order Pages Size (4KB pages)
0 1 4 KB
1 2 8 KB
2 4 16 KB
3 8 32 KB
10 1024 4 MB

Comparison Summary

Feature kmalloc vmalloc kvmalloc
Max size ~128KB GBs GBs
Physically contiguous Yes No Maybe
Speed Fast Slower Depends
DMA-able Yes No Maybe
Atomic context With GFP_ATOMIC No No

Size and Alignment

Checking Actual Size

size_t actual = ksize(ptr);  /* Actual allocated size */

Aligned Allocation

/* kmalloc returns naturally aligned memory */
/* For larger alignments: */
ptr = kmalloc(size + alignment - 1, GFP_KERNEL);
aligned_ptr = PTR_ALIGN(ptr, alignment);

/* Or use page allocator for page alignment */

Error Handling

/* Always check for allocation failure */
ptr = kmalloc(size, GFP_KERNEL);
if (!ptr) {
    pr_err("Failed to allocate %zu bytes\n", size);
    return -ENOMEM;
}

/* Safe pattern for structure with members */
struct complex {
    char *name;
    void *buffer;
    int *array;
};

struct complex *create_complex(int array_size)
{
    struct complex *c;

    c = kzalloc(sizeof(*c), GFP_KERNEL);
    if (!c)
        return NULL;

    c->name = kstrdup("test", GFP_KERNEL);
    if (!c->name)
        goto err_name;

    c->buffer = kmalloc(4096, GFP_KERNEL);
    if (!c->buffer)
        goto err_buffer;

    c->array = kmalloc_array(array_size, sizeof(int), GFP_KERNEL);
    if (!c->array)
        goto err_array;

    return c;

err_array:
    kfree(c->buffer);
err_buffer:
    kfree(c->name);
err_name:
    kfree(c);
    return NULL;
}

Memory Debugging

Enable kernel config options for debugging:

CONFIG_DEBUG_SLAB=y
CONFIG_SLUB_DEBUG=y
CONFIG_KASAN=y  # Kernel Address Sanitizer

Runtime debugging:

# Enable SLUB debugging at boot
slub_debug=FZPU

# For specific cache
slub_debug=FZPU,kmalloc-64

Best Practices

Do

/* DO: Use sizeof on the variable, not the type */
struct my_struct *p = kmalloc(sizeof(*p), GFP_KERNEL);

/* DO: Use kzalloc when you need zeroed memory */
p = kzalloc(sizeof(*p), GFP_KERNEL);

/* DO: Use array functions for arrays */
arr = kmalloc_array(count, sizeof(*arr), GFP_KERNEL);

/* DO: Check allocation success */
if (!ptr)
    return -ENOMEM;

Don’t

/* DON'T: Use sizeof on the type */
struct my_struct *p = kmalloc(sizeof(struct my_struct), flags);

/* DON'T: Multiply sizes manually (overflow risk) */
arr = kmalloc(count * sizeof(*arr), flags);

/* DON'T: Forget to free on error paths */
/* DON'T: Double free */
/* DON'T: Use after free */

Summary

  • Use kmalloc()/kzalloc() for general small allocations
  • Use vmalloc() for large allocations that don’t need physical contiguity
  • Use kvmalloc() when size varies
  • Always check return values
  • Use array variants for overflow protection
  • Match allocator with context (GFP flags)

Next

Learn about GFP flags to control allocation behavior.


Back to top

Linux Driver Development Guide is a community resource for learning kernel driver development. Not affiliated with the Linux Foundation. Content provided for educational purposes.

This site uses Just the Docs, a documentation theme for Jekyll.