2020-05-23
關鍵字:kmalloc、kzalloc、kcalloc
1、kmalloc()
kmalloc() 是Linux內核開發中最常使用的申請內存的函數。它的原型如下所示:
#include <linux/slab.h> void *kmalloc(size_t size, int flags);
函數的返回值通常就指向所申請到的內存空間的起始地址。當然,有時它也會指向 NULL--如果內存的申請出於某些原因失敗的話。
參數 1 表示要申請的空間大小,單位是字節。size_t 其實就是個 unsigned int 的別名。
參數 2 表示申請內存時的模式。這個模式有很多個可選類型,它們均聲明於 <linux/gfp.h> 中。雖然在 gfp.h 中有眾多可選類型,但其實最常用的也就兩個值:
1、GFP_KERNEL
這個標志表示當內核中的可用內存不足時,調用者,即發起當前申請請求的進程將會被強制進入休眠狀態以等待有足夠的內存可供申請為止。也正因為這個標志有可能導致調用進程的休眠,這個標志只被允許在“進程上下文”中使用。“中斷上下文”如果要休眠的話是會引發錯誤的。
2、GFP_ATOMIC
內核會額外地將一部分內存划分出來以專供於原子性的空間申請使用。簡單來說,使用這個標志就是有內存時就給你分配,沒有就直接以失敗告終,它不會讓你的進程進入休眠態的。
需要注意的是:以上的頭文件貼出的僅僅是標准Linux內核中的聲明。不同版本、用途的Linux內核可能會有不同的聲明結構,這些需要各位同學自行確認。
以下是一個使用 kmalloc() 函數申請內存的小實例:
struct Person{ char *name; int age; }; int __init m_init() { struct Person *p = (struct Person *)kmalloc(sizeof(struct Person), GFP_KERNEL); return 0; }
2、kzalloc()
kzalloc()函數其實不需要介紹。因為它在本質上就是 kmalloc() 函數,只不過多了一個自動幫我們把所申請到的內存清零的操作而已。
我們直接看一下這個函數的原型聲明就了然了。這個函數位於 <linux/slab.h> 頭文件中:
/** * 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); }
既然如此,kzalloc() 的示例代碼就沒有必要貼了。
3、kcalloc()
kcalloc()函數的本質也是 kmalloc() 函數。它相較於 kzalloc() 函數又多了一層“數量”的封裝。閑話少說,直接看下它的原型:
/** * kcalloc - allocate memory for an array. The memory is set to zero. * @n: number of elements. * @size: element size. * @flags: the type of memory to allocate (see kmalloc). */ static inline void *kcalloc(size_t n, size_t size, gfp_t flags) { return kmalloc_array(n, size, flags | __GFP_ZERO); }
kmalloc_array()函數的原型如下:
static inline void *kmalloc_array(size_t n, size_t size, gfp_t flags) { if (size != 0 && n > SIZE_MAX / size) return NULL; return __kmalloc(n * size, flags); }
繞了一圈,又是 kmalloc() 的封裝。既然如此,就沒有貼示例代碼的必要了。
4、空間的釋放
前面貼了三種內存空間申請的函數,它們在本質上都是同一個函數 kmalloc() 的封裝。
因此,通常來說,要釋放申請的內存都可以用同一個函數來完成:
#incclude <linux/slab.h> void kfree(const void *);