Heng30的博客
搜索 分类 关于 订阅

Linux内核如何动态分配内存?

2025-03-08

动态内存分配是一个很重要的功能,如果没有动态内存分配,所有的变量都分配到堆上,堆栈很容易就会溢出。动态内存分配一般都是用来分配需要长期使用的内存或大块的内存。不过在Linux内核中,分配内存会比在应用层要复杂。下面就给了一个小例子。

常用函数和参数

  • kmalloc:虚拟/物理地址是连续的

  • kzalloc:会将内存初始化为0, 虚拟/物理地址是连续的

  • kvmalloc:不限制内存大小,但是只保证虚拟内存地址连续,物理地址空间不一定连 续。并且可能会产生阻塞或休眠

  • GFP_KERNEL:分配内存时可能会阻塞或休眠

  • GFP_ATOMIC:分配内存时不会休眠

测试代码

//simple.c

#include <linux/init.h>
#include <linux/kernel.h>
#include <linux/module.h>
#include <linux/slab.h>
#include <linux/string.h>

static int __init simple_init(void) {
    /* ===================== kmalloc =================== */
    char *ptr_1 = kmalloc(64, GFP_KERNEL);
    if (!ptr_1) {
        pr_err("kmalloc 64 bytes failed\n");
    } else {
        kfree(ptr_1);
        pr_info("kmalloc 64 bytes ok\n");
    }

    /* ===================== kzalloc =================== */
    char *ptr_2 = kzalloc(64, GFP_KERNEL);
    if (!ptr_2) {
        pr_err("kzalloc 64 bytes failed\n");
    } else {
        kfree(ptr_2);
        pr_info("kzalloc 64 bytes ok\n");
    }

    /* ===================== kvmalloc =================== */
    const int max_memory_size = 1024 * 1024;
    char *ptr_3 = kvmalloc(2 * max_memory_size, GFP_KERNEL);
    if (!ptr_3) {
        pr_err("kvmalloc %d bytes failed\n", 2 * max_memory_size);
    } else {
        kfree(ptr_3);
        pr_info("kvmalloc %d bytes ok\n", 2 * max_memory_size);
    }

    return 0;
}

static void __exit simple_exit(void) { pr_info("simple_exit\n"); }

module_init(simple_init);
module_exit(simple_exit);

MODULE_LICENSE("GPL");
MODULE_AUTHOR("heng30");
MODULE_VERSION("v0.0.1");
MODULE_DESCRIPTION("A simple kernel module");

Makefile编译脚本

#!/bin/sh

top-dir = $(shell pwd)
kernel-version = $(shell uname -r)
kernel-dir ?= /lib/modules/$(kernel-version)/build

obj-m += simple.o

all:
        make -C $(kernel-dir) modules M=$(top-dir)

clean:
        rm -f *.o *.ko *.mod *.mod.c *.order *.symvers
        make -C $(kernel-dir) clean m=$(top-dir)

测试

  • 安装驱动:insmod simple.ko

  • 移除驱动:rmmod simple.ko