kmalloc,vmalloc,malloc區別

簡單的說:

  1. kmalloc和vmalloc是分配的是內核的內存,malloc分配的是用戶的內存
  2. kmalloc保證分配的內存在物理上是連續的,vmalloc保證的是在虛擬地址空間上的連續,malloc不保證任何東西
  3. kmalloc能分配的大小有限(128Kb),vmalloc和malloc能分配的大小相對較大
  4. 內存只有在要被DMA訪問的時候才需要物理上連續
  5. vmalloc比kmalloc要慢

 

詳細的解釋:

      對於提供了MMU(存儲管理器,輔助操作系統進行內存管理,提供虛實地址轉換等硬件支持)的處理器而言,Linux提供了複雜的存儲管理系統,使得進程所能訪問的內存達到4GB。

      進程的4GB內存空間被人爲的分爲兩個部分--用戶空間與內核空間。用戶空間地址分佈從0到3GB(PAGE_OFFSET,在0x86中它等於0xC0000000),3GB到4GB爲內核空間。

      內核空間中,從3G到vmalloc_start這段地址是物理內存映射區域(該區域中包含了內核鏡像、物理頁框表mem_map等等),比如我們使用 的 VMware虛擬系統內存是160M,那麼3G~3G+160M這片內存就應該映射物理內存。在物理內存映射區之後,就是vmalloc區域。對於 160M的系統而言,vmalloc_start位置應在3G+160M附近(在物理內存映射區與vmalloc_start期間還存在一個8M的gap 來防止躍界),vmalloc_end的位置接近4G(最後位置系統會保留一片128k大小的區域用於專用頁面映射)

      kmalloc和get_free_page申請的內存位於物理內存映射區域,而且在物理上也是連續的,它們與真實的物理地址只有一個固定的偏移,因此存在較簡單的轉換關係,virt_to_phys()可以實現內核虛擬地址轉化爲物理地址:
   #define __pa(x) ((unsigned long)(x)-PAGE_OFFSET)
   extern inline unsigned long virt_to_phys(volatile void * address)
   {
        return __pa(address);
   }
上面轉換過程是將虛擬地址減去3G(PAGE_OFFSET=0XC000000)。

與之對應的函數爲phys_to_virt(),將內核物理地址轉化爲虛擬地址:
   #define __va(x) ((void *)((unsigned long)(x)+PAGE_OFFSET))
   extern inline void * phys_to_virt(unsigned long address)
   {
        return __va(address);
   }
virt_to_phys()和phys_to_virt()都定義在include/asm-i386/io.h中。

而vmalloc申請的內存則位於vmalloc_start~vmalloc_end之間,與物理地址沒有簡單的轉換關係,雖然在邏輯上它們也是連續的,但是在物理上它們不要求連續。

vmalloc()函數爲了把物理上不連續的頁面轉換爲虛擬地址空間上連續的頁,必須專門建立頁表項。還有,通過vmalloc()獲得的頁必須一個一個的進行映射(因爲它們物理上不是連續的),這就會導致比直接內存映射大得多的緩衝區刷新。因爲這些原因,vmalloc()僅在絕對必要時纔會使用——典型的就是爲了獲得大塊內存時,例如,當模塊被動態插入到內核中時,就把模塊裝載到由vmalloc()分配的內存上

malloc的實現原理

malloc函數的實質體現在,它有一個將可用的內存塊連接爲一個長長的列表的所謂空閒鏈表(全局變量,一個內存塊的鏈表指針)。調用malloc函數時,它沿連接表尋找一個大到足以滿足用戶請求所需要的內存塊。然後,將該內存塊一分爲二(一塊的大小與用戶請求的大小相等,另一塊的大小就是剩下的字節)。接下來,將分配給用戶的那塊內存傳給用戶,並將剩下的那塊(如果有的話)返回到連接表上。調用free函數時,它將用戶釋放的內存塊連接到空閒鏈上。到最後,空閒鏈會被切成很多的小內存片段,如果這時用戶申請一個大的內存片段,那麼空閒鏈上可能沒有可以滿足用戶要求的片段了。於是,malloc函數請求延時,並開始在空閒鏈上翻箱倒櫃地檢查各內存片段,對它們進行整理,將相鄰的小空閒塊合併成較大的內存塊。  malloc()在操作系統中的實現    在 C 程序中,多次使用malloc () 和 free()。


我們用下面的程序來演示kmalloc、get_free_page和vmalloc的區別:
#include <linux/module.h>
#include <linux/slab.h>
#include <linux/vmalloc.h>
MODULE_LICENSE("GPL");
unsigned char *pagemem;
unsigned char *kmallocmem;
unsigned char *vmallocmem;

int __init mem_module_init(void)
{
//最好每次內存申請都檢查申請是否成功
//下面這段僅僅作爲演示的代碼沒有檢查
pagemem = (unsigned char*)get_free_page(0);
printk("<1>pagemem addr=%x", pagemem);

kmallocmem = (unsigned char*)kmalloc(100, 0);
printk("<1>kmallocmem addr=%x", kmallocmem);

vmallocmem = (unsigned char*)vmalloc(1000000);
printk("<1>vmallocmem addr=%x", vmallocmem);

return 0;
}

void __exit mem_module_exit(void)
{
free_page(pagemem);
kfree(kmallocmem);
vfree(vmallocmem);
}

module_init(mem_module_init);
module_exit(mem_module_exit);

我們的系統上有160MB的內存空間,運行一次上述程序,發現pagemem的地址在0xc7997000(約3G+121M)、kmallocmem 地址在0xc9bc1380(約3G+155M)、vmallocmem的地址在0xcabeb000(約3G+171M)處,符合前文所述的內存佈局。

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章