10.31 Linux物理內存管理

在內核態申請內存比在用戶態申請內存要更為直接,它沒有采用用戶態那種延遲分配內存技術。內核認為一旦有內核函數申請內存,那麼就必須立刻滿足該申請內存的請求,並且這個請求一定是正確合理的。相反,對於用戶態申請內存的請求,內核總是儘量延後分配物理內存,用戶進程總是先獲得一個虛擬內存區的使用權,最終通過缺頁異常獲得一塊真正的物理內存。

1.物理內存的內核映射

IA32架構中內核虛擬地址空間只有1GB大小(從3GB到4GB),因此可以直接將1GB大小的物理內存(即常規內存)映射到內核地址空間,但超出1GB大小的物理內存(即高端內存)就不能映射到內核空間。為此,內核採取了下面的方法使得內核可以使用所有的物理內存。

1.高端內存不能全部映射到內核空間,也就是說這些物理內存沒有對應的線性地址。不過,內核為每個物理頁框都分配了對應的頁框描述符,所有的頁框描述符都保存在mem_map數組中,因此每個頁框描述符的線性地址都是固定存在的。內核此時可以使用alloc_pages()和alloc_page()來分配高端內存,因為這些函數返回頁框描述符的線性地址。

2.內核地址空間的後128MB專門用於映射高端內存,否則,沒有線性地址的高端內存不能被內核所訪問。這些高端內存的內核映射顯然是暫時映射的,否則也只能映射128MB的高端內存。當內核需要訪問高端內存時就臨時在這個區域進行地址映射,使用完畢之後再用來進行其他高端內存的映射。

由於要進行高端內存的內核映射,因此直接能夠映射的物理內存大小隻有896MB,該值保存在high_memory中。內核地址空間的線性地址區間如下圖所示:

Linux物理內存管理

從圖中可以看出,內核採用了三種機制將高端內存映射到內核空間:永久內核映射,固定映射和vmalloc機制。

2.物理內存管理機制

基於物理內存在內核空間中的映射原理,物理內存的管理方式也有所不同。內核中物理內存的管理機制主要有夥伴算法,slab高速緩存和vmalloc機制。其中夥伴算法和slab高速緩存都在物理內存映射區分配物理內存,而vmalloc機制則在高端內存映射區分配物理內存。

夥伴算法

夥伴算法負責大塊連續物理內存的分配和釋放,以頁框為基本單位。該機制可以避免外部碎片。

per-CPU頁框高速緩存

內核經常請求和釋放單個頁框,該緩存包含預先分配的頁框,用於滿足本地CPU發出的單一頁框請求。

slab緩存

slab緩存負責小塊物理內存的分配,並且它也作為高速緩存,主要針對內核中經常分配並釋放的對象。

vmalloc機制

vmalloc機制使得內核通過連續的線性地址來訪問非連續的物理頁框,這樣可以最大限度的使用高端物理內存。

3.物理內存的分配

內核發出內存申請的請求時,根據內核函數調用接口將啟用不同的內存分配器。

3.1 分區頁框分配器

分區頁框分配器 (zoned page frame allocator) ,處理對連續頁框的內存分配請求。分區頁框管理器分為兩大部分:前端的管理區分配器和夥伴系統,如下圖:

Linux物理內存管理

管理區分配器負責搜索一個能滿足請求頁框塊大小的管理區。在每個管理區中,具體的頁框分配工作由夥伴系統負責。為了達到更好的系統性能,單個頁框的申請工作直接通過per-CPU頁框高速緩存完成。

該分配器通過幾個函數和宏來請求頁框,它們之間的封裝關係如下圖所示。

Linux物理內存管理

這些函數和宏將核心的分配函數__alloc_pages_nodemask()封裝,形成滿足不同分配需求的分配函數。其中,alloc_pages()系列函數返回物理內存首頁框描述符,__get_free_pages()系列函數返回內存的線性地址。

3.2 slab分配器

slab 分配器最初是為了解決物理內存的內部碎片而提出的,它將內核中常用的數據結構看做對象。slab分配器為每一種對象建立高速緩存。內核對該對象的分配和釋放均是在這塊高速緩存中操作。一種對象的slab分配器結構圖如下:

Linux物理內存管理

可以看到每種對象的高速緩存是由若干個slab組成,每個slab是由若干個頁框組成的。雖然slab分配器可以分配比單個頁框更小的內存塊,但它所需的所有內存都是通過夥伴算法分配的。

slab高速緩存分專用緩存和通用緩存。專用緩存是對特定的對象,比如為內存描述符創建高速緩存。通用緩存則是針對一般情況,適合分配任意大小的物理內存,其接口即為kmalloc()。

3.3 非連續內存區內存的分配

內核通過vmalloc()來申請非連續的物理內存,若申請成功,該函數返回連續內存區的起始地址,否則,返回NULL。vmalloc()和kmalloc()申請的內存有所不同,kmalloc()所申請內存的線性地址與物理地址都是連續的,而vmalloc()所申請的內存線性地址連續而物理地址則是離散的,兩個地址之間通過內核頁表進行映射。

vmalloc()的工作方式理解起來很簡單:

1.尋找一個新的連續線性地址空間;

2.依次分配一組非連續的頁框;

3.為線性地址空間和非連續頁框建立映射關係,即修改內核頁表;

vmalloc()的內存分配原理與用戶態的內存分配相似,都是通過連續的虛擬內存來訪問離散的物理內存,並且虛擬地址和物理地址之間是通過頁表進行連接的,通過這種方式可以有效的使用物理內存。但是應該注意的是,vmalloc()申請物理內存時是立即分配的,因為內核認為這種內存分配請求是正當而且緊急的;相反,用戶態有內存請求時,內核總是儘可能的延後,畢竟用戶態跟內核態不在一個特權級。


分享到:


相關文章: