1. 程式人生 > >Linux核心空間記憶體申請函式kmalloc、kzalloc、vmalloc的區別

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() 的共同特點是:

  1. 用於申請核心空間的記憶體;
  2. 記憶體以位元組為單位進行分配;
  3. 所分配的記憶體虛擬地址上連續;

kmalloc()、kzalloc()、vmalloc() 的區別是:

  1. kzalloc 是強制清零的 kmalloc 操作;(以下描述不區分 kmalloc 和 kzalloc)
  2. kmalloc 分配的記憶體大小有限制(128KB),而 vmalloc 沒有限制;
  3. kmalloc 可以保證分配的記憶體實體地址是連續的,但是 vmalloc 不能保證;
  4. kmalloc 分配記憶體的過程可以是原子過程(使用 GFP_ATOMIC),而 vmalloc 分配記憶體時則可能產生阻塞;
  5. kmalloc 分配記憶體的開銷小,因此 kmalloc 比 vmalloc 要快;

一般情況下,記憶體只有在要被 DMA 訪問的時候才需要物理上連續,但為了效能上的考慮,核心中一般使用 kmalloc(),而只有在需要獲得大塊記憶體時才使用 vmalloc()。例如,當模組被動態載入到核心當中時,就把模組裝載到由 vmalloc() 分配的記憶體上。