1 API
在 linux 内核空间中申请内存,我们一般会用到 kmalloc()、 kzalloc()、 vmalloc()
void *kmalloc(size_t size, gfp_t flags)
void kfree(const void *addr)
//当内核中设备被卸载时, 使用 devm_kzalloc(或 devm_kmalloc)分配的内存会被自动释放
void *devm_kzalloc(struct device *dev, size_t size, gfp_t gfp)
void *devm_kmalloc(struct device *dev, size_t size, gfp_t gfp)
void *vmalloc(unsigned long size);
void vfree(const void *addr);
kzalloc()函数与 kmalloc()非常相似,参数及返回值是一样的,
kzalloc()函数除了申请内存空间之外,还会对申请到的内存空间进行清零。
同样 kzalloc()对应的内存释放函数也是kfree()。
vmalloc()函数则会在虚拟内存空间给出一块连续的内存区域,
但这片连续的虚拟内存在物理内存中并不一定连续。
由于 vmalloc()没有保证申请到的是连续的物理内存,
因此对申请的内存大小没有限制,如果需要申请较大的内存
空间就需要用此函数了。
size:需要分配的内存大小
flags:分配内存时所使用的标志位,这些 flag 定义在 include/linux/gfp.h
返回值:申请成功返回的就是内存的起始地址,申请失败返回 NULL。
#define GFP_ATOMIC (__GFP_HIGH|__GFP_ATOMIC|__GFP_KSWAPD_RECLAIM)
#define GFP_KERNEL (__GFP_RECLAIM | __GFP_IO | __GFP_FS)
#define GFP_KERNEL_ACCOUNT (GFP_KERNEL | __GFP_ACCOUNT)
#define GFP_NOWAIT (__GFP_KSWAPD_RECLAIM)
#define GFP_NOIO (__GFP_RECLAIM)
#define GFP_NOFS (__GFP_RECLAIM | __GFP_IO)
#define GFP_USER (__GFP_RECLAIM | __GFP_IO | __GFP_FS | __GFP_HARDWALL)
#define GFP_DMA __GFP_DMA
#define GFP_DMA32 __GFP_DMA32
#define GFP_HIGHUSER (GFP_USER | __GFP_HIGHMEM)
#define GFP_HIGHUSER_MOVABLE (GFP_HIGHUSER | __GFP_MOVABLE)
#define GFP_TRANSHUGE_LIGHT ((GFP_HIGHUSER_MOVABLE | __GFP_COMP | \
__GFP_NOMEMALLOC | __GFP_NOWARN) & ~__GFP_RECLAIM)
#define GFP_TRANSHUGE (GFP_TRANSHUGE_LIGHT | __GFP_DIRECT_RECLAIM)
GFP_ATOMIC: 分配内存的过程是一个原子过程,分配内存的过程不会被(高优先级进程或中断)打断。
GFP_KERNEL:内核空间中正常的内存分配过程,也是用的最多的 flag。
GFP_KERNEL_ACCOUNT: GFP_KERNEL_ACCOUNT 与 GFP_KERNEL 相同,只是分配是由 kmemcg 负责
GFP_DMA: 给 DMA 控制器分配内存,需要使用该标志( DMA 要求分配虚拟地址和物理地址连续)。
2 总结
一般情况下,内存只有在被 DMA 访问的时候才需要物理上连续,但为了性能上的考虑,内
核中一般使用 kmalloc(),而只有在需要获得大块内存时才使用 vmalloc()。