淺談使用者空間和核心空間記憶體分配
阿新 • • 發佈:2018-11-30
一、使用者空間動態申請記憶體:
1、malloc:
malloc分配的記憶體大小至少為size引數所指定的位元組數malloc的返回值是一個指標,指向一段可用記憶體的起始地址
多次呼叫malloc所分配的地址不能有重疊部分,除非某次malloc所分配的地址被釋放掉
malloc應該儘快完成記憶體分配並返回(不能使用NP-hard的記憶體分配演算法)
實現malloc時應同時實現記憶體大小調整和記憶體釋放函式(realloc和free)
注:malloc和free函式是配對的,如果申請後不釋放就是記憶體洩露;如果無故釋放那就是什麼都沒有做,釋放只能釋放一次,如果釋放兩次及兩次以上會出現錯誤(但是釋放空指標例外,釋放空指標其實也等於什麼都沒有做,所以,釋放多少次都是可以的)
2、new
new返回指定型別的指標,並且可以自動計算所需要的大小。而malloc則必須由我們計算位元組數,並且在返回的時候強轉成實際指定型別的指標。
注:new和delete函式是配使用的
這裡malloc分配的記憶體空間在邏輯上是連續的,而在物理上可以不連續。
二、核心空間中申請記憶體:
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() 分配的記憶體上。