簡述:linux
一、kmalloc和vmalloc是分配的是內核的內存,malloc分配的是用戶的內存
二、kmalloc保證分配的內存在物理上是連續的,內存只有在要被DMA訪問的時候才須要物理上連續,malloc和vmalloc保證的是在虛擬地址空間上的連續
函數
三、kmalloc能分配的大小有限,vmalloc和malloc能分配的大小相對較大佈局
四、vmalloc比kmalloc要慢。盡 管在某些狀況下才須要物理上連續的內存塊,可是不少內核代碼都用kmalloc來得到內存,而不是vmalloc。這主要是出於性能的考慮。 vmalloc函數爲了把物理內存上不連續的頁轉換爲虛擬地址空間上連續的頁,必須專門創建頁表項。糟糕的是,經過vmalloc得到的頁必須一個個地進 行映射,由於它們物理上是不連續的,這就會致使比直接內存映射大得多的TLB抖動,vmalloc僅在不得已時纔會用--典型的就是爲了得到大塊內存時。性能
詳解:ui
【malloc的實現原理】spa
malloc函數的實質體如今, 它有一個將可用的內存塊鏈接爲一個長長的列表的所謂空閒鏈表(全局變量,一個內存塊的鏈表指針)。調用malloc函數時,它沿鏈接表尋找一個大到足以滿 足用戶請求所須要的內存塊。而後,將該內存塊一分爲二(一塊的大小與用戶請求的大小相等,另外一塊的大小就是剩下的字節)。接下來,將分配給用戶的那塊內存 傳給用戶,並將剩下的那塊(若是有的話)返回到鏈接表上。調用free函數時,它將用戶釋放的內存塊鏈接到空閒鏈上。到最後,空閒鏈會被切成不少的小內存 片斷,若是這時用戶申請一個大的內存片斷,那麼空閒鏈上可能沒有能夠知足用戶要求的片斷了。因而,malloc函數請求延時,並開始在空閒鏈上翻箱倒櫃地 檢查各內存片斷,對它們進行整理,將相鄰的小空閒塊合併成較大的內存塊。 malloc()在操做系統中的實現 在 C 程序中,屢次使用malloc () 和 free()。不過,您可能沒有用一些時間去思考它們在您的操做系統中是如何實現的。本節將向您展現 malloc 和 free 的一個最簡化實現的代碼,來幫助說明管理內存時都涉及到了哪些事情。 在大部分操做系統中,內存分配由如下兩個簡單的函數來處理: void *malloc (long numbytes):該函數負責分配 numbytes 大小的內存,並返回指向第一個字節的指針。 void free(void *firstbyte):若是給定一個由先前的 malloc 返回的指針,那麼該函數會將分配的空間歸還給進程的「空閒空間」。操作系統
【kmolloc】.net
kmalloc是經過cache來實現的, 只不過每次kmalloc的大小不一樣, 所以是從不一樣的cache中分配.用於kmalloc可分配的內存大小範圍在32~131027(128k)字節,而且因爲它用 slab分配器來分配內存的,因此,獲得的內存大小可能比你申請的要大一些(它向上取2的N次冪整數)。並且若是開啓了 CONFIG_LARGE_ALLOCS選項,這個值能夠更大,能夠達到了32M。指針
對於提供了MMU(存儲管理器,輔助操做系統進行內存管理,提供虛實地址轉換等硬件支持)的處理器而言,Linux提供了複雜的存儲管理系統,使得進程所能訪問的內存達到4GB。blog
進程的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之間,與物理地址沒有簡單的轉換關係,雖然在邏輯上它們也是連續的,可是在物理上它們不要求連續。
咱們用下面的程序來演示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)處,符合前文所述的內存佈局。
引用:
http://blog.csdn.net/macrossdzh/article/details/5958368
http://blog.csdn.net/fangjian1204/article/details/39738293?utm_source=tuicool&utm_medium=referral