(該圖轉自http://bbs.chinaunix.net/thread-2018659-2-1.html,作者Aryang)
下面對各部分進行概述。
Linux進程的線性地址空間(進程虛擬地址空間分佈),0~3G是User地址空間,3~4G是Kernel地址空間。(適用於ARM、X86等,mips按0~2G,2~3G劃分)
關於線性地址佈局,此圖未說明部分:
1.緊接着內核數據區向上是mem_map全局page數組。
2. kernel啓動地址並非是0xC0000000,而是PAGE_OFFSET+TEXT_OFFSET(0x8000),而在這32k大小的空間存放着內核一級頁表數組swapper_pg_dir(每一項一級頁表4個字節,映射1M內存,4G空間共4K項一級頁表,佔用16k內存),頁表在啓動階段setup_arch->paging_init中調用prepare_page_table()和map_lowmem()進行初始化和映射,將在另一篇詳細敘述。
3.內核動態加載驅動模塊so將被load到緊接着MODULES_VADDR~0xC0000000的16M空間。
小於896M的物理內存直接映射到內核3G~3G+896M線性地址空間內,VA=PA-PHYS_OFFSET+PAGE_OFFSET
大約896M的物理內存通過建立各級頁表的方式映射到高端映射區。
每個task在起task_struct內都有一個指針mm指向mm_struct,其控制着該task的所有內存信息,其成員mmap指向vma區鏈表,pgd指向頁全局目錄位置。
切換任務時要爲下一個task裝載其pgd到C2(X86爲cr3)。
在cpu尋址時,mmu將虛擬地址按照2級映射方式,映射到對應物理葉匡的地址偏移上去。
而在內存管理上,系統啓動階段使用的是Bootmem,它是以簡單的bitmap方式(0:未使用,1:已用)。
系統啓動後buddy接手內存管理(以頁爲單位),分爲兩種情況,per_cpu_pageset和free_area,前者用來分配單個頁(在Linux物理內存描述三個層級中有詳細描述),後者用來分配多頁的情況,11個鏈表管理頁塊的大小從2^1~2^11,每個鏈表中又分爲不同遷移類型的子鏈表。
#define MIGRATE_UNMOVABLE 0
#define MIGRATE_RECLAIMABLE 1
#define MIGRATE_MOVABLE 2
#define MIGRATE_PCPTYPES 3 /* the number of types on the pcp lists */
#define MIGRATE_RESERVE 3
#define MIGRATE_ISOLATE 4 /* can't allocate from here */
MIGRATE_TYPES是爲了有效解決內存碎片問題而引入的,將可移動(用戶空間申請的內存可以重新映射)、不可移動(內核空間通常申請的)、可回收(文件映射)等組織在不同的鏈表中,申請內存時按照不同情況在各自類型的鏈表中釋放,如果所在類型內存不足,會fallback到其他類型鏈表繼續分配。在系統初始化完成時全部內存劃分給MOVABLE類型鏈表,當有其他類型需求時再從MOVABLE中釋放生成。
slab分配器是面向對象的分配機制,其建立在buddy基礎之上,細節待另一篇詳述。
框架
(該圖轉自bullbat的博客,強烈推薦該博客http://blog.csdn.net/bullbat/article/details/7166140)