目录
在内核开发、驱动编写,甚至日常应用开发中,我们经常会遇到三种不同的内存分配接口:malloc
、kmalloc
和 vmalloc
。它们虽然名字相似,但应用场景和内部实现却有很大不同。
1. malloc(用户态内存分配)
-
适用环境:用户空间(user space)
-
函数原型:
void *malloc(size_t size);
-
本质:
malloc
是 C 语言标准库函数,它的本质是通过系统调用(如brk
、mmap
)向操作系统申请内存。 -
特点:
-
位于用户空间,不能直接访问内核资源。
-
分配的是虚拟内存,由操作系统的内存管理机制(如页表)进行映射。
-
返回的地址对于当前进程是有效的,但其他进程无法直接访问。
-
✨
malloc
使用方便,但在内核模块里是不能使用的(因为内核模块运行在内核态)。
2. kmalloc(内核态物理连续内存分配)
-
适用环境:内核空间(kernel space)
-
函数原型:
void *kmalloc(size_t size, gfp_t flags);
-
本质:
kmalloc
是 Linux 内核提供的内存分配函数,用来分配物理上连续的一段内存。 -
特点:
-
适合需要高速访问或者用于 DMA(直接内存访问)场景。
-
分配的是物理上连续的一块内存,且虚拟地址连续。
-
分配小块内存(一般不超过 128KB,实际受限于系统配置)。
-
使用 GFP 参数(如
GFP_KERNEL
、GFP_ATOMIC
)控制分配行为。 -
分配完后要用
kfree
释放。
-
✨
kmalloc
适合小块、快速的内核态内存分配,但当内存碎片严重或者分配大块内存时容易失败。
3. vmalloc(内核态虚拟连续内存分配)
-
适用环境:内核空间(kernel space)
-
函数原型:
void *vmalloc(unsigned long size);
-
本质:
vmalloc
也是内核提供的分配接口,但它分配的是虚拟地址连续、物理地址不一定连续的内存。 -
特点:
-
可以分配比
kmalloc
更大的内存块(比如几 MB 甚至更多)。 -
分配的是虚拟地址连续的内存块,内部通过多个物理页进行映射。
-
访问速度相对于
kmalloc
分配的内存会稍慢,因为需要额外的地址转换。 -
适合用于大块但访问速度要求不高的内核内存。
-
分配完要用
vfree
释放。
-
✨
vmalloc
是解决大块内存申请需求的重要手段,虽然慢一点,但胜在大而稳定。
4. 总结对比表
特性 | malloc | kmalloc | vmalloc |
---|---|---|---|
使用空间 | 用户空间 | 内核空间 | 内核空间 |
连续性 | 虚拟地址连续 | 虚拟+物理地址连续 | 虚拟地址连续、物理不一定连续 |
速度 | 快 | 很快 | 相对较慢 |
大小适用范围 | 小到大 | 小(<128KB) | 大(MB甚至更多) |
释放函数 | free | kfree | vfree |
应用场景 | 应用程序开发 | 驱动开发/小内存块 | 驱动开发/大内存块 |
5. 小Tips
-
在内核中,绝对不能使用
malloc
!要用kmalloc
或vmalloc
。 -
如果你需要的内存小且需要物理连续(比如 DMA),就用
kmalloc
。 -
如果你需要的内存比较大,且对访问速度要求不那么高,就用
vmalloc
。 -
kmalloc
+GFP_ATOMIC
是紧急情况下(比如中断处理)使用的快速分配,不可睡眠。 -
记得配对释放:
malloc
->free
,kmalloc
->kfree
,vmalloc
->vfree
。