一、實體記憶體的分配
1.Linux2.6支援非一致記憶體訪問(NUMA),被分為一節點,每一個節點內是UMA
80x86系統不使用NUMA,因為只有一個節點
每個節點分為3個管理區:ZONE_DMA , ZONE_NORMAL , ZONE_HIGHMEM
2.3個管理區的分布與特點見表格:
| |
ZONE_DMA |
ZONE_NAORMAL |
ZONE_HIGHMEM |
| 物理位址範圍 |
低於16MB的物理頁框 DMA不經過MMU提供的地址映射,導致(1)外部裝置直接存取物理的地址(前16MB)(2)DMA不能依靠MMU將連續的線性地址映射到不連續的物理地址。因此前16MB地址的分配與定址需要特殊處理。 |
高於16MB,低於896MB的物理頁框 上限不一定是896MB,這隻是一個最大值 若實體記憶體高於1G,就無法訪問(因為核心態的線性地址只有1G),因此從線性地址中取最高128MB,用於間接映射,前896MB用於線性映射,因此這個值是896MB不是1G |
高於896MB的物理頁框 與線性地址最高128MB建立非線性映射 64位硬體平台上,ZONE_HIGHMEM是空的。因為可使用的線性空間遠大於可安裝的RAM大小 |
| 使用方式 |
(1)可由老式的基於ISA的裝置通過DMA使用 (2)可由CPU直接存取,線性地址0xc0000000=物理地址 |
可由CPU直接存取,線性地址0xc0000000=物理地址 |
不能由CPU直接存取 |
| 映射方式 |
線性映射到線性地址第4個G的前16MB空間 |
線性映射到線性地址第4個B的16-896MB空間 |
非線性地映射到線性地址第4個G的剩餘空間,見“高端記憶體的頁框的核心映射” |
3.Linux核心安裝在從物理地址0x00100000開始的地址(ZONE_DMA),
圖中上面的標號是頁框號,不是物理地址。
這是前3MB的RAM,從物理地址0x00100000開始,依次是核心代碼、核心資料。
二、核心頁表
1.什麼是核心頁表?參見Linux2.6虛擬記憶體管理
主核心頁全域目錄的最高目錄項部分作為參考模型,為系統中每個普通進程對應的頁全域目錄項提供參考模型
2.核心頁表的初始化
(1)第一階段:建立一個臨時頁表
(2)第二階段:核心充分地利用剩餘的RAM並適當地建立分頁表。
3.建立臨時核心頁表
分析:
(1)頁面大小為4KB + 一個頁表項指向一個頁面 + 一頁頁表有1024個頁表項 ------> 一頁頁表可以映射4MB內容
(2)假設核心初始化所需要的內容都能容納於RAM的前8MB
核心初始化所需要的內容 = 核心使用的程式碼片段、資料區段 + 臨時頁表 + 128KB的記憶體範圍(用於存放動態資料結構)
(3)(1)+(2)-----> 需要2頁臨時頁表
建立映射:
(1)臨時頁全域目錄存放在swapper_pg_dir中,其中第0、0x300指向第一個頁表,第1、0x301指向第二個頁表
(2)臨時頁表存放在的_end開始的位置,這兩頁頁表指向前8MB的物理空間
4.建立最終核心頁表
.(1)RAM<896MB -----> 不啟用PAE,沒有ZONE_HIGHMEM
物理地址與3G以上線性地址建立線性映射,即線性地址-0xc0000000=物理地址
(2)RAM > 896MB && RAM < 4096MB
前896MB的物理地址與3G以上的物理地址建立線性映射,即線性地址-0xc0000000=物理地址
896MB-----4096MB的物理地址與3G+896MB-----4G的空間建議非線性映射,見“高端記憶體的頁框的核心映射”
(3)RAM>4086MB ----->啟用PAE,使用三級分頁模型
(4)核心空間與物理RAM的映射關係,圖見Linux地址映射(1)--線性映射與非線性映射
四、對於大片連續記憶體的管理---夥伴系統
1.為什麼要引入夥伴系統?
(1)能夠滿足大片連續的記憶體配置
DMA忽略分頁單元而直接存取地址匯流排,因此,所請求的緩衝區必須位於連續的頁框中
(2)能夠解決外片段問題
2.原理
把所有的空閑框分為11個塊鏈表
每個塊鏈表的大小分別包含大小為1,2,4,8,16,32,64,512,1024個連續的頁框
不同管理區使用不同的夥伴系統
分配時,選擇能滿足需求的最小的連續頁框的鏈表,取分,分配,把剩下的鏈入相應大小的隊列
回收時,如果可以就合并
四、對於小記憶體區的分配和管理 ----- slab
見Linux2.6為資料結構分配記憶體-slab
五、為使用者空間分配一個實體記憶體的過程:
所有直線箭頭都是從左向右,有一個弧線箭頭是往回指的
六、物理頁面的回收
1.物理頁面分配的來源:
(1)當前尚存的空閑頁面
(2)不活躍的乾淨頁面
(3)不活躍的髒頁面
2.kswapd的作用:
(1)預先找出若干頁面,且將這些頁面的映射斷開,使這些頁面從活躍狀態轉入不活躍狀態
(2)把已經處於不活躍的髒頁面寫入交換裝置,使它們成為不活躍的乾淨頁面,或進一步回收成為空白閑頁面
3.kswapd需要在代碼中顯示地調用schedule()來進行調度,因為:
每當CPU結束一次系統調用或中斷服務,從系統空間返回時,就會檢查調度標誌。kswapd是個核心線程,永遠不會回到使用者空間,就可能會繞過這個機制而佔住CPU不放,所以只能靠自律,自己在可能需要運行較長時間的操作之前調用schedule()