最近看了一篇論文,覺得裡面對linux記憶體管理的講解還比較可以,就做了點筆記記錄下來。
使用者空間:
1. 使用malloc()函數在進程的堆上分配記憶體。
2. Malloc()函數其實是調用brk()系統調用分配記憶體,該函數的作用是以頁面大小擴大或縮小堆空間,但分配的時候還是以位元組為單位進行分配,所以malloc()函數可以動態地分配記憶體大小。
實體記憶體管理:
1. 分頁機制(減少了外部片段)
2. 為了分配連續記憶體,降低TLB的重新整理率,採用“夥伴系統”管理實體記憶體(頁)。
3. 夥伴系統提供的兩個分配實體記憶體的函數:get_free_page()和get_free_pages(),前者只分配單頁,後者分配2n物理頁。
4. 在linux系統中每一頁實體記憶體用struct page描述,所有的物理頁儲存在一個全域數組中mem_map[]中,可以通過該數組尋找到所有的物理頁。
Slab:
1. 其實就是一個提前分配的記憶體池,裡面的記憶體是重複利用的,避免頻繁建立和銷毀帶來的開銷。
2. 建立在夥伴系統之上,可以很好利用硬體緩衝提高訪問速度。
3. 將夥伴系統提高的物理頁分成眾多小記憶體塊以供分配,用來滿足核心經常發生的對小於一頁的小記憶體配置(減少內部片段)。
4. Kmem_cache_alloc()和kmem_cache_free()函數提供對核心專用對象(固定大小、結構體)的記憶體配置和銷毀。
5. Kmalloc()分配小記憶體塊,記憶體配置粒度更靈活,可分配32~131072(128K)大小範圍的記憶體;kmalloc()分配的函數分配的空間被稱為核心邏輯地址,由於其是連續分配的,而且首地址一定,所以與物理地址的映射只需要減去一個固定的位移量(PAGE_OFFSET),其對應的頁表屬於核心頁表(swapper_pg_dir),在系統初始化時就已建立。
6. Slab不僅為上面兩種記憶體配置保留了記憶體,而且還為DMA準備一部分記憶體。
核心非連續記憶體配置(Vmalloc):
1. 將非連續的記憶體塊(頁)整合成大塊記憶體,用於分配(徹底消除外部片段)。
2. 借鑒了使用者空間分配的虛擬記憶體,記憶體邏輯上是連續的,但實際上實體記憶體並不一定是連續的;和使用者進程相似,核心也有一個名為init_mm的mm_struct結構來描述核心地址空間,其中頁表項pdg=swapper_pg_dir包含了系統核心空間的映射關係。
3. 可以分配很大的記憶體空間,最大可以將近1G(幾百M),但需要對核心虛擬位址重新對應,更新核心表,因此分配效率上要抵一些。
比較:
1. vmalloc()和get_free_page()/kmalloc()分配的核心虛擬記憶體位於不同的區間。由get_free_page()和kmalloc()分配的連續記憶體都位於物理映射地區,而由vmalloc()分配的記憶體為與物理映射地區之後的高地址區。其位置分布如所示:
2. kmalloc()和kmem_cache_alloc()的主要區別就是前者可以分配動態大小的記憶體,而後者不行,只能分配固定大小的記憶體。如果記憶體大小(常量)是固定的話,kmalloc()函數是調用kmem_cache_alloc()函數實現,所以基本沒區別。如果記憶體大小是變化的,就只能選kmalloc()了。總體來說,kmem_cache_alloc()分配效率要比kmalloc()高一些。
附1 使用者空間和核心空間記憶體映射原理圖