Linux kernel zone有如下類型:ZONE_DMA, ZONE_NORMAL和ZONE_HIGHMEM。
每一種zone類型適合不同的使用類型:
ZONE_DMA是低端實體記憶體範圍適合於ISA裝置的請求,ZONE_DMA的物理頁框映射到kernel線性地址空間。
ZONE_NORMAL則被直接映射到kernel線性地址空間,常見的核心操作都發生在ZONE_NORMAL。
ZONE_HIGHMEM則是剩餘的可用記憶體,核心不會對這部分記憶體做直接映射。
由於核心地址空間有限,不會對HIGHMEM做直接地址映射,因此核心是無法直接操作HIGHMEM空間內的頁框。但是核心可以通過以下方式把HIGHMEM映射到kernel地址空間:
1. 使用pkmap臨時映射
2. fixmap固定地址映射
3. vmalloc 分配非連續記憶體區
此外進程可以把Highmem映射到進程的使用者地址空間。
使用pkmap做臨時映射
核心在fixmap 線性地址前保留了一個2M/4M的線性地址空間,通過pkmap把高端記憶體臨時映射到這個空間,pkmap是一段很小的地址空間:只有2M或者4M。
使用fixmap映射做固定地址映射
Fixmaps是核心預留的一塊虛擬位址空間,可以映射到任意的實體記憶體,因此我們可以認為fixmap也會使用到highmem,fixmaps地址空間也非常有限,典型的位址範圍為0xFFC00000~0xFFFFF000。
kernel 分配非連續記憶體區
vmalloc會優先使用HIGHMEM zone來分配頁框,只有從HIGHMEM zone分配失敗,才會從Normal zone分配。
使用者空間映射
雖然核心地址空間有限,但是每個進程的使用者地址空間都可以達到3G,Highmem的頁框可以不受限制的映射到使用者線性地址空間。當訪問使用者地址空間地址發生缺頁異常時,核心的page allocator會優先從highmem zone分配頁面,只有當highmem zone沒有足夠的空閑頁面時,才會選擇Normal或者DMA zone進行分配。
因此highmem記憶體的主要使用者是應用進程的頁面映射,核心kernel通過pkmap fixmap方式,同時使用的Highmem記憶體,理論上最多2MB/4MB + 3.xMB;由於Highmem的存在,使得應用地址空間缺頁異常處理,檔案對應,堆分配等操作優先使用highmem zone的記憶體,減輕了Normal zone的分配壓力,某種程度上避免了Normal區的片段化。我們甚至可以禁止使用者空間地址的HIGH_MEM分配使用Normal zone和 DMA zone,使得Normal DMA只用於核心地址空間記憶體的分配,盡量減少片段化,避免記憶體配置失敗。我想這就是HighMem存在的意義吧。