Linux核心空間記憶體申請函式kmalloc、kzalloc、vmalloc的區別
我們都知道在使用者空間動態申請記憶體用的函式是 malloc(),這個函式在各種作業系統上的使用是一致的,對應的使用者空間記憶體釋放函式是 free()。注意:動態申請的記憶體使用完後必須要釋放,否則會造成記憶體洩漏,如果記憶體洩漏發生在核心空間,則會造成系統崩潰。
那麼,在核心空間中如何申請記憶體呢?一般我們會用到 kmalloc()、kzalloc()、vmalloc() 等,下面我們介紹一下這些函式的使用以及它們之間的區別。
kmalloc() |
函式原型:
void *kmalloc(size_t size, gfp_t flags);
kmalloc() 申請的記憶體位於實體記憶體對映區域,而且在物理上也是連續的,它們與真實的實體地址只有一個固定的偏移,因為存在較簡單的轉換關係,所以對申請的記憶體大小有限制,不能超過128KB。
較常用的 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
對應的記憶體釋放函式為:
void kfree(const void *objp);
kzalloc() |
kzalloc() 函式與 kmalloc() 非常相似,引數及返回值是一樣的,可以說是前者是後者的一個變種,因為 kzalloc() 實際上只是額外附加了 __GFP_ZERO 標誌。所以它除了申請核心記憶體外,還會對申請到的記憶體內容清零。
/**
* 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() 對應的記憶體釋放函式也是 kfree()。
vmalloc() |
函式原型:
void *vmalloc(unsigned long size);
vmalloc() 函式則會在虛擬記憶體空間給出一塊連續的記憶體區,但這片連續的虛擬記憶體在實體記憶體中並不一定連續。由於 vmalloc() 沒有保證申請到的是連續的實體記憶體,因此對申請的記憶體大小沒有限制,如果需要申請較大的記憶體空間就需要用此函數了。
對應的記憶體釋放函式為:
void vfree(const void *addr);
注意:vmalloc() 和 vfree() 可以睡眠,因此不能從中斷上下文呼叫。
總結 |
kmalloc()、kzalloc()、vmalloc() 的共同特點是:
- 用於申請核心空間的記憶體;
- 記憶體以位元組為單位進行分配;
- 所分配的記憶體虛擬地址上連續;
kmalloc()、kzalloc()、vmalloc() 的區別是:
- kzalloc 是強制清零的 kmalloc 操作;(以下描述不區分 kmalloc 和 kzalloc)
- kmalloc 分配的記憶體大小有限制(128KB),而 vmalloc 沒有限制;
- kmalloc 可以保證分配的記憶體實體地址是連續的,但是 vmalloc 不能保證;
- kmalloc 分配記憶體的過程可以是原子過程(使用 GFP_ATOMIC),而 vmalloc 分配記憶體時則可能產生阻塞;
- kmalloc 分配記憶體的開銷小,因此 kmalloc 比 vmalloc 要快;
一般情況下,記憶體只有在要被 DMA 訪問的時候才需要物理上連續,但為了效能上的考慮,核心中一般使用 kmalloc(),而只有在需要獲得大塊記憶體時才使用 vmalloc()。例如,當模組被動態載入到核心當中時,就把模組裝載到由 vmalloc() 分配的記憶體上。