閱讀《Understanding Linux Kernel Memory Management》整理的核心概念筆記,涵蓋記憶體佈局、分頁管理、分配器架構與 NUMA 感知設計。
一、系統初始化與記憶體佈局 (x86)
- 啟動階段:建立兩個臨時頁表映射 0~8MB 與 3GB~3GB+8MB 至物理 0~8MB。
- 核心頁表初始化:
kernel_physical_mapping_init(),啟用 PSE(大頁)與 PGE(全域頁)固定 TLB。
- 固定映射:核心空間固定映射至
0xC0000000(3GB)。
- ZONE_DMA:0~16 MB
- ZONE_NORMAL:16~896 MB
- ZONE_HIGHMEM:896 MB~
- x86_64 無 HIGHMEM,直接映射所有物理記憶體。
二、kmap 與 HIGHMEM 存取
kmap():將 HIGHMEM 頁映射至核心位址空間,可能睡眠。
kmap_atomic():中斷上下文專用,預留頁表項,必須快速釋放。
三、Buddy Allocator(夥伴系統)
- 頁級分配器,管理 2 的冪次連續物理頁框。
- 核心 API:
alloc_pages(gfp_mask, order) 回傳 struct page 陣列。
- 同時作為 Slab 分配器後端與 Page Cache 後端。
四、資源受限時的策略
- Bounce Buffer:DMA 區記憶體不足時,以空間換生命週期。
- kmap_atomic():頁表項稀缺時,用完即釋。
五、NUMA 與 Node
- SMP 擴展瓶頸 → NUMA:每顆 CPU 擁有本地記憶體。
- 核心結構
pg_data_t 描述 Node,分配策略優先滿足本地 Node。
六、Slab 分配器與核心記憶體 API
- 專用快取:
kmem_cache_alloc/free(),針對固定結構(如 task_struct、inode)。
- 通用分配:
kmalloc/kfree(),背後為多組不同大小的 Slab 快取。
- 非高頻分配場景直接用
kmalloc() 即可。
七、頁表架構
- x86 三級頁表(PGD/PMD/PTE)為 PAE 設計。
- x86_64 採四級頁表(P4D/PUD/PMD/PTE)。
八、常見誤區
struct address_space 描述的是 Page Cache/檔案映射,非使用者位址空間(後者為 mm_struct)。
- GFP = Get Free Pages 旗標組合,非單一分配器。
掌握各層次機制,才能在效能調校與驅動開發中做出正確決策。