导读:本期聚焦于小伙伴创作的《Linux内存管理相关的几个函数分别有什么作用和使用场景》,敬请观看详情。不少人在调试内核模块时发现申请内存后系统直接崩溃,根源往往是选错了分配函数。Linux内核提供了多套内存管理接口,各自面向不同的地址空间与上下文。比如kmalloc用于分配物理连续的小块内核内存,适用于中断上下文;vmalloc分配虚拟连续但物理未必连续的大块空间;mmap则让用户态进程把设备内存或文件映射到自身地址空间。理解这些函数的差异,能避免内存泄漏与非法访问。本文从原理层面说明其实现机制、参数含义与典型用例,并给出可运行的内核代码片段,帮助你在驱动开发或性能优化时做出正确选择。

在Linux系统中,内存管理涉及用户态与内核态两套体系,各自提供不同的函数来满足分配、映射和释放需求。内核开发者若混淆了这些接口的适用边界,轻则造成内存浪费,重则触发oops或死锁。本文围绕几个最关键的函数展开,说明它们背后的分配逻辑与真实工程中的用法。

Linux内存管理相关的几个函数分别有什么作用和使用场景

kmalloc与kfree:内核小块物理连续内存

kmalloc是内核中最常用的分配函数之一,它从slab分配器中获取内存,保证返回的虚拟地址所对应的物理页是连续的。这一特性对DMA操作至关重要,因为硬件设备通常只能识别物理地址。函数原型为void *kmalloc(size_t size, gfp_t flags),其中flags控制分配行为,例如GFP_KERNEL允许睡眠,而GFP_ATOMIC用于中断上下文。

下面的代码展示了一个内核模块中分配与释放结构体的典型做法。注意错误分支必须调用kfree,否则会产生内存泄漏。

#include <linux/slab.h>
#include <linux/module.h>

struct my_data {
    int id;
    char buf[64];
};

static int __init demo_init(void)
{
    struct my_data *p;
    p = kmalloc(sizeof(struct my_data), GFP_KERNEL);
    if (!p)
        return -ENOMEM;
    p->id = 1;
    printk("alloc ok, addr=%pn", p);
    kfree(p);
    return 0;
}
module_init(demo_init);

使用kmalloc的缺点在于它受限于物理内存碎片,无法分配过大空间,通常建议不超过128KB。若需要更多内存且不需物理连续,应考虑vmalloc。

vmalloc与vfree:大块虚拟连续内存

vmalloc分配的是虚拟地址连续、物理地址未必连续的内存,它通过对页表进行映射来实现。因为要建立页表,分配开销比kmalloc大,且不能用于DMA。适合在模块加载时分配较大的缓冲区,例如网络子系统的一些表项。

以下片段演示了vmalloc的基本使用。分配失败同样需要处理,并且必须用vfree释放。

#include <linux/vmalloc.h>

static int __init vdemo_init(void)
{
    void *buf;
    buf = vmalloc(1024 * 1024);
    if (!buf)
        return -ENOMEM;
    memset(buf, 0, 1024 * 1024);
    printk("vmalloc 1MB at %pn", buf);
    vfree(buf);
    return 0;
}

vmalloc分配的地址访问稍慢,因为可能涉及多级页表查询,但在需要大块内存且物理连续不重要的场景里,它是唯一可行的内核选项。

mmap:用户态映射内核或文件资源

mmap是用户态系统调用,也能通过驱动中的file_operations->mmap在内核侧实现,把设备内存或内核缓冲暴露给用户进程,避免频繁copy_to_user。典型驱动用remap_pfn_range完成映射。

内核侧实现可参考下面简化代码,将一段保留内存映射到用户空间。

#include <linux/mm.h>

static int my_mmap(struct file *filp, struct vm_area_struct *vma)
{
    unsigned long pfn = virt_to_phys(kernel_buf) >> PAGE_SHIFT;
    return remap_pfn_range(vma, vma->vm_start, pfn,
                           vma->vm_end - vma->vm_start,
                           vma->vm_page_prot);
}

用户态调用mmap时,参数prot与flags决定权限与是否共享。错误使用MAP_FIXED可能覆盖已有映射,应谨慎。借助mmap,用户程序能以内存读写方式操作硬件寄存器,大幅提升吞吐。

函数对比与选型建议

为方便理解,下面用表格列出三者核心差异:

函数空间位置物理连续典型场景
kmalloc内核小对象、DMA
vmalloc内核大缓冲
mmap用户依赖后端设备访问

实践中,中断处理函数只能用GFP_ATOMIC的kmalloc;初始化阶段可用vmalloc预备大结构;驱动暴露资源给用户选mmap。明确这些边界,才能让内存管理既安全又高效。

linux_memory_managementmmapkmalloc修改时间:2026-08-09 15:51:27

免责声明:​ 已尽一切努力确保本网站所含信息的准确性。网站内容多为原创整理与精心编撰,观点力求客观中立。本站旨在免费分享,内容仅供个人学习、研究或参考使用。若引用了第三方作品,版权归原作者所有。如内容涉及您的权益,请联系我们处理。
内容垂直聚焦
专注技术核心技术栏目,确保每篇文章深度聚焦于实用技能。从代码技巧到架构设计,为用户提供无干扰的纯技术知识沉淀,精准满足专业提升需求。
知识结构清晰
覆盖从开发到部署的全链路。AI、前端、编程、数据库、服务器、建站、系统层层递进,构建清晰学习路径,帮助用户系统化掌握开发与运维所需的核心技术。
深度技术解析
拒绝泛泛而谈,深入技术细节与实践难点。无论是数据库优化还是服务器配置,均结合真实场景与代码示例进行剖析,致力于提供可直接应用于工作的解决方案。
专业领域覆盖
精准对应开发生命周期。从前端界面到后端编程,从数据库操作到服务器运维,形成完整闭环,一站式满足全栈工程师和运维人员的技术需求。
即学即用高效
内容强调实操性,步骤清晰、代码完整。用户可根据教程直接复现和应用于自身项目,显著缩短从学习到实践的距离,快速解决开发中的具体问题。
持续更新保障
专注既定技术方向进行长期、稳定的内容输出。确保各栏目技术文章持续更新迭代,紧跟主流技术发展趋势,为用户提供经久不衰的学习价值。