kmalloc、kzalloc、vmalloc都是用于驱动程序中获取指定大小可用内存的函数,我们都知道内核不能直接使用内存地址访问内存。内核运行的地址(虚拟地址)比内存大,某些虚拟地址地址经过映射后对应内存地址,内核运行在虚拟地址状态。这样,对虚拟地址的访问,就变成对与虚拟地址有映射关系的内存地址的访问(物理内存地址)。
对kmalloc、kzalloc、vmalloc的解释参考:https://blog.csdn.net/lu_embedded/article/details/51588902
kmalloc、kzalloc、vmalloc函数原型:
/**
* kmalloc - allocate memory
* @size: how many bytes of memory are required.
* @flags: the type of memory to allocate (see kcalloc).
*
* kmalloc is the normal method of allocating memory
* in the kernel.
*/
static __always_inline void *kmalloc(size_t size, gfp_t flags)
{
return __kmalloc_node(size, flags, -1);
}
/**
* kzalloc - allocate memory. The memory is set to zero.
* @size: how many bytes of memory are required.
* @flags: the type of memory to allocate (see kmalloc).
*/
static inline void *kzalloc(size_t size, gfp_t flags)
{
return kmalloc(size, flags | __GFP_ZERO);
}
/*
* vmalloc - allocate virtually continguos memory
*
* @size: allocation size
*
* Allocate enough pages to cover @size from the page level
* allocator and map them into continguos kernel virtual space.
*
* For tight control over page level allocator and protection flags
* use __vmalloc() instead.
*/
void *vmalloc(unsigned long size)
{
return __vmalloc(size, GFP_KERNEL | __GFP_HIGHMEM, PAGE_KERNEL);
}
较常用的 flags(分配内存的方法):
GFP_ATOMIC —— 分配内存的过程是一个原子过程,分配内存的过程不会被(高优先级进程或中断)打断;
GFP_KERNEL —— 正常分配内存;
GFP_DMA —— 给 DMA 控制器分配内存,需要使用该标志(DMA要求分配虚拟地址和物理地址连续)。
flags 的参考用法:
|– 进程上下文,可以睡眠 GFP_KERNEL
|– 进程上下文,不可以睡眠 GFP_ATOMIC
| |– 中断处理程序 GFP_ATOMIC
| |– 软中断 GFP_ATOMIC
| |– Tasklet GFP_ATOMIC
|– 用于DMA的内存,可以睡眠 GFP_DMA | GFP_KERNEL
|– 用于DMA的内存,不可以睡眠 GFP_DMA |GFP_ATOMIC
注:上下文指的是“开始至结束”之间的过程。
参考上面链接博客的内容:
kmalloc()、kzalloc()、vmalloc() 的共同特点是:
- 用于内申请内核空间的存;
- 内存以字节为单位进行分配;
- 所分配的内存虚拟地址上连续;
kmalloc()、kzalloc()、vmalloc() 的区别是:
- kzalloc 是强制清零的 kmalloc 操作;(以下描述不区分 kmalloc 和 kzalloc)
- kmalloc 分配的内存大小有限制(128KB),而 vmalloc 没有限制;
- kmalloc 可以保证分配的内存物理地址是连续的,但是 vmalloc 不能保证;
- kmalloc 分配内存的过程可以是原子过程(使用 GFP_ATOMIC),而 vmalloc 分配内存时则可能产生阻塞;
- kmalloc 分配内存的开销小,因此 kmalloc 比 vmalloc 要快;
总结:
-
kmalloc用于分配连续的内存地址(物理地址),kzalloc把kmalloc分配的内存地址清零。
-
vmalloc分配不连续的内存地址,基于这个特点,它可以用于分配大块的不连续的内存空间(物理地址)。
-
不论是kmalloc还是vmalloc,他们分配的内存空间(物理地址)对应的虚拟地址都是连续的,内核中访问到的地址都是先虚拟地址,经过页表转换(实际上虚拟地址是通过页表机制与内存形成对应关系的)内存地址。因此,可以使用循环对虚拟地址读取或写入,与分配的内存地址是否联系无关。