並且建立記憶體區段物件

Download Report

Transcript 並且建立記憶體區段物件

Windows 記憶體管理
第5組
• 記憶體管理概述
– 分頁式記憶體管理
– 徐勝斌
4.1 記憶體管理概述
• 在Intel x86 系統架構中,記憶體位址有三種類型:
– 實體位址
• 即記憶體儲存器的索引,當CPU操縱記憶體晶片時,它透過位址線腳
位價上電子信號來讀取或寫入相關的記憶體單元。
– 虛擬位址(又稱線性位址)
• 在邏輯位址轉換為實體位址的過程中,會先產生對應的虛擬位址。之
後遵循分頁的機制,再由虛擬位址產生實體位址。
– 邏輯位址
• 由CPU所產生的位址,稱為邏輯位址(logical address)。
• 要執行時,程式的這些部分在經過一些必要的處理之後,會變成對記
憶體有意義的位址值。
CPU
Logical
Address
0004
Physical
+ Address
Base
Register 1000
1004
Memory
4.1 記憶體管理概述
• 把一個位址告訴CPU,讓它存取相對應的實體記憶體
單元,這一過程是OS和CPU相互合作來完成的。
– CPU最終需要的是一個實體位址,所以他必須把軟體指令中
的位址轉譯成實體位址
– 從OS的角度來看,需要有效的管理實體記憶體,使Process
需要記憶體時,可以分配足夠的記憶體給這個Process
– 每個Process有邏輯上獨立的位址空間,不同Process的位址空
間應該是相互隔離的
• 在一個 Process 1使用位址 A來存取 一個 記 憶體單元,與另外一個
Process 2中用位址A存取的記憶體單元是不同的實體記憶體,這樣只
可以避免有意或無意的侵入到另外一個Process的位址空間中。
4.1 記憶體管理概述
• 虛擬記憶體(Virtual Memory)
– 當系統中Process數量增加時,所需的記憶體數量往往超過了
總實體記憶體
– 一般的做法是把不緊急的Process中的資料或程式碼先存放到
外部記憶體,而把它們佔用的實體記憶體騰出來給緊急
Process使用
– 好處:
• 允許Program Size大於Physical Memory Size仍能執行
• 程式撰寫者專心負責寫好程式,無須考量Program Size太大之問題
• Memory utilization 提升
Disk
Memory
SWAP out
SWAP in
4.1.1 分頁式記憶體管理
• 在分頁式記憶體管理中,虛擬位址空間是按頁(page)
來管理的,對應於實體記憶體也是按照頁(page)來管
理,實體記憶體中的頁面有時後稱為分頁框架(page
frame)
– 在虛擬位址空間中連續的頁面對應於實體記憶體中的頁面可
以不必是連續的
– 實體頁面可以被動態地分配給特定的虛擬頁面
虛擬位址
空間
實體位址
空間
虛擬頁面與實體頁面之間的對應
4.1.1 分頁式記憶體管理
• 動態變動分區之Memory Management
– 在Multi programming 之下,系統(Memory)內存在有多個Process執
行,而且各個Process之大小並不相同,進入系統及完成工作的時
間也不盡相同
– 若採”Contiguous Allocation”,即系統要分配給Process夠大的連續
可用空間,Process才能載入執行
• “Extended Fragmentation” Problem :沒有足夠大的連續性空間可以配
置給Process使用
• “Internal Fragmentation” Problem :配置給Process的Memory空間大於
Process實際所需空間
Memory
Process 1
150 K
Allocated
Process 5
300 K
Process 6
Free
實
際
Process
Process
OS配置的
所
Memory
佔
Space
空
間
內部碎裂(Internal Fragmentation)
4.1.1 分頁式記憶體管理
• 有了頁面(page)劃分機制後,每個虛擬位址32位元資訊中
分成兩部分:頁索引+頁內偏移
– 根據頁索引去查Page Table,取得該Page之對應載入頁框之起始為
址+頁偏移量即得Physical Address.
虛擬位址
Page #
Memory
Page offset
Page table
0
f2
1
f4
2
f5
+
f0
f1
f2
f3
f4
f5
會有Internal Fragmentation問題,
因為user program size不見得是
Page size的整數倍
eq: page size = 4KB
process size = 21 KB
=>須配 6 個 Frame
=>內部碎裂: 24 – 21 = 3 KB
4.1.1 分頁式記憶體管理
• Intel x86採用分級分頁表的方式來管理
– 32位元的虛擬位址頁索引被分為頁目錄索引(10位元)和分頁表索引(10位
元)
– 分頁目錄項目(PDE, Page Directory Entry) :210 = 1024項的分頁表
– 分頁表項目(PTE, Page Table Entry) :210 = 1024項的頁面
31
22 21
分頁目錄索引
12 11
分頁表索引
頁內偏移
0
頁面
分頁表(PTE)
分頁目錄(PDE)
1. 二級分頁表結構好處是,當
虛擬位址空間中實際使用的
記憶體比例較小時,很多分
頁表不必在記憶體中建構出
來
2. 要付出效能的代價,在解析
一個虛擬位址時,需要兩次
查表動作
4.1.1 分頁式記憶體管理
• 位址轉譯快查緩衝區(TLB, Translation Look-aside Buffer)
– 為了避免在分級分頁表解析過程中多次查表導致效能下降問題
– 包含最近使用過的頁面的記憶體對應資訊
– 在Intel x86 處理器中,TLB是完全由硬體來維護的
1. 到 TLB 查 詢 有 無 對 應 的
Page Number存在
2. 若 Hit, 則輸 出 Frame 起 始
位址
3. 若Miss,則到Memory中取
出Page Table查詢,已取
得Frame起始位址
4.1.1 分頁式記憶體管理
• 實體位址擴充(PAE, Physical Address Extension)
– 支援36位元實體位址,即64GB實體記憶體
– 但虛擬位址仍然是32位元
– 分頁目錄和分頁表中的每一項為64位元,可以描述更長的實體位址
• 區段式記憶體管理
985402024 黃郁誠
4.1.2 區段式記憶體管理
除了用虛擬位址來實作有效和靈活的記憶體管理以外
另一種記憶體管理方式是將實體記憶體劃分成若干個區段
(segment).
計算實體記憶體位址方式:
“ 區段基址 + 偏移”
每個區段可以有它自己的存取屬性, 包括讀寫屬性、特權
等級等。
例如,Intel x86的處理器中,有專門的區段暫存器,允許每
行指令在存取記憶體時,指定在哪個區段上進行。
4.1.2 區段式記憶體管理
區段概念在Intel 8086/8088 真實模式中已經使用了,但當時
區段的用途是擴充位址範圍,將系統的記憶體從64K擴充
到1MB。
Intel 8086/8088都是16位元的,但位址線有20條。為了存取
整個位址範圍,處理器的作法,將區段暫存器中的值左移4
位元再加上一個16位元址值。
最大的位址值:
(64K-1)*16+(64K-1) = 1,114,095B
Intel 80286 (24位元位址),在保護模式下:區段變成一個索
引:指向段描述項表中的某一個段描述項,而段描述項才
真正指定了區段的基底位址、區段長度以及一些保護屬性。
Intel 80386以後,處理器中的暫存器才真正轉移到32位元
14
4.1.2 區段式記憶體管理
Intel x86中,邏輯位址的區段部分稱為區段選擇符(segment
selector),指定了區段的索引以及要存取的特權等級。
區段暫存器cs、ss、ds、es、 fs 和gs專門用於指定一個位址的
區段選擇符,其中有三個區段暫存器有特殊的用途。
cs :程式暫存器,指向一個包括指令的區段。
ss :堆疊段暫存器,指向一個包含目前呼叫推疊的區段。
ds :資料區段暫存器,指向一個包含全域和靜態資料的區段。
15
4.1.2 區段式記憶體管理
雖然定指暫存器和資料暫存器都是32位元,但是區段選擇
只有16位元,如下圖所示:
15
3
1
0
表指示
目前特權等級
位址
區段索引
一 個 段 描述 項 表 只包 含
213=8192的區段
2
GDT or LDT
GDT : 全域段描述項表
請求者的目前特
權等級(0~3)
LDT : 區域區段描述項表
區段選擇符格式
16
4.1.2 區段式記憶體管理
段描述項表格式:
區段內最大偏移(0-15)
基底位址(0-15)
1
DPL
S 類型
基底位址(24-31)
S: 0 表示系統區段
1 表示普通區段
DPL:描述項套全等級
基底位址(16-23)
D/
G
0
B
區段內最大偏移(16-19)
未使用(作業系統可使用)
區段偏移位址32位元(1)或1位元(0)
粒度標誌,最大偏移欄位位元組(0)
頁面(1)單位
17
4.1.2 區段式記憶體管理
G :當G = 0,指長度單位為位元組
G = 1 時,長度單位為4096位元組
區段長度可以達到220*4096 = 4GB =整個32位元線性位址
空間。
DPL :允許存取此區段的最低特權等級,
例如,DPL 為0的區段只能當CPL=0時才可以存取。
DPL 為3個區段可由任何CPL的程式碼存取。
類型:指定了區段的類型,包括程式段、資料段、TSS區段
和LDT區段。
18
4.1.2 區段式記憶體管理
GDT 和 LDT
GDT︰系統全域範圍內有效的一張表,包含最多8192的段
描述項,所以一張表需要8192*8 =64KB記憶體空間
19
4.1.2 區段式記憶體管理
Intel x86 “區段+偏移” 形式的邏輯位址的解析過程
GDT
gdtr
區段基底位址
0

1
ldtr
LDT
線性位址
(32位元)
區段基底位址
偏移(32位元)
區段
索引
表指示位址
目前特權等級
20
4.1.2 區段式記憶體管理
系統全域共同的空間可以透過GDT來安排案存取。此外,
每個行程私有的資料和程式碼存放在LDT中,因而行程切
換時,只需改變LDT表,就實作了行程私有位址的切換。
區段式記憶體管理和分頁式記憶體管理並不是對立的,它
們可以組合起來在同一個系統使用。
“ 區段基址 + 偏移”
虛擬位址
區段式記憶體
管理單元
實體位址
分頁式記憶體管
理單元
Intel x86邏輯位址個完整解析過程
21
4.1.3 記憶體管理演算法介紹
記憶體管理演算法分為兩類:
點陣圖標記法:假設整個待分配記憶體的大小為N位元組,
管理記憶體的粒度為M位元組,並且N=M*K,也就是說,
記憶體管理的基本單元為M位元組,現在共有K個單元需要
動態管理。
為了記錄這K個記憶體管理單元的使用情況,點陣圖標記
法是用一個共有K個位元的點陣圖,其中每一位元的值(0或
1)說明了這一位元所對應的記憶體單元是否空閒。
由於點陣圖精確地記錄了每一個記憶體單元的空閒或已
被使用的情況,所以,當記憶體管理員接收到一個新的記
憶體申請時,他只需掃描點陣圖,就能確定是否有合適的
空閒記憶體可以滿足請求。
22
4.1.3 記憶體管理演算法介紹
N
點陣圖標技法的實作需要額外的記憶體負擔,通常為 N * 8
所以,只需適當地選取M,就可以控制這部分額外的負擔。
使用者請求記憶體大小不一定是M位元組的倍數,因而在
分配記憶體時,平均為M/2位元組的浪費。
記憶體管理員在分配記憶體時需要掃描連續個0位元,此操
作並不高效率(複雜度O(K))
23
4.1.3 記憶體管理演算法介紹
空閒串列法:使用串列來描述已分配的空閒塊。
初始時,整個區塊被當作一個大的空閒區塊加入到空閒串
列中。
當記憶體管理元接收到一個記憶體分配請求時,從空閒串
列中找到一個合適的、能提供足夠記憶體的空閒區塊,並
且從該空閒區塊中分離出足夠多的記憶體,交給客戶,剩
下的記憶體仍然是一個空閒區塊,而且分配的記憶體加入
到已分配記憶體串列中。
24
4.1.3 記憶體管理演算法介紹
當記憶體管理元接收到一個記憶體分配請求時,會使用不
同的測略來搜尋適當的空閒區塊:
1. 先適法(first-fit): 從空閒串列中找到第一個滿足客戶請求的空閒區塊。
2. 佳適法(best-fit): 從空閒串列中找到最接近於客戶請求大小的空閒區塊。
3. 差適法(worst-fit): 從空閒串列中找到最大的空閒區塊。
4. 次適法(next-fit): 從空閒串列的目前位置往後掃描,找到第一個滿足客戶
請求的空閒區塊。
25
頁面替換演算法
Page Replacement Algorithms
985402001 索維廷
按需分頁(demand paging)
• 行程所需資料最初所有頁面都在磁碟上
• 隨著控制流不斷前進,行程獲得越來越多實體記憶體頁面,
趨向平滑
• 記憶體頁面的請求和滿足透過中斷或例外的方式來完成
按需分頁(demand paging)
程式A的工作集
程式B的工作集
工作集理論模型
t代表時間點
δ代表一段時間間隔
w(t, δ)代表行程的工作集
頁面替換演算法
• 實體記憶體吃緊
• 行程使用的頁面總數超過系統中頁面的數
量
• 需要一個有效率的實體記憶體管理替換頁
面的演算法
頁面替換演算法
• 最佳頁面替換演算法
(The Optimal Page Replacement Algorithm)
• 最近未使用頁面替換演算法
(The Not Recently Used Page Algorithm)
• 先進先出頁面替換演算法
(The First-In First-out Page Replacement Algorithm)
• 第二次機會頁面替換演算法
(The Second Chance Page Replacement Algorithm)
• 最近最不常使用頁面替換演算法
(The Least Recently Used Page Replacement Algorithm)
• 最不常用頁面替換演算法
(The Not Frequently Used Page Replacement Algorithm)
最佳頁面替換演算法
(The Optimal Page Replacement Algorithm)
• 分頁錯誤比率最低
• 替換未來最不可能被使用到的分頁
• 保證在頁框的數目固定之下,會得到最少的分頁錯誤次數
• 實際上無法實作,因為對於未來將要使用的分頁不可能完
全預測成功
• 可提供分頁替換演算法的比較基準
最佳頁面替換演算法
(The Optimal Page Replacement Algorithm)
最近未使用頁面替換演算法
(The Not Recently Used Page Algorithm)
– 存取位元R
– 修改位元M
– 此 2 位元(R, M)有下列 4 種組合,依據順序進行替換
• (0, 0):表示最近沒有被行程使用,也沒有被行程修改,是
最佳的替換分頁
• (0, 1):表示最近沒有被行程使用,但是已經被修改過,此
分頁須先寫回磁碟後,才可進行替換
• (1, 0):表示最近曾被行程使用,但是沒被修改過,由於可
能再次被使用,故盡量不要替換此分頁
• (1, 1):表示最近曾被行程使用,也被修改過,所以需寫回
磁碟中,是最差的替換分頁選擇
先進先出頁面替換演算法
(The First-In First-out Page Replacement Algorithm)
• 每次有新的分頁需置入時,會選擇置入記憶體時間最久的
分頁換出
• 兩種實作的方法:
– 記錄每個分頁被置入到頁框的時間,當每次需要換出
分頁時,會找置入時間最早的一頁
– 利用 FIFO 佇列來實作,當要進行分頁替換時,就把佇
列最前端的分頁換出,再把要置入的分頁放到佇列的
末端
• Belady 反常:配置的頁框數目增加,分頁錯誤次數有可能
會增加
先進先出頁面替換演算法
(The First-In First-out Page Replacement Algorithm)
第二次機會頁面替換演算法
(The Second Chance Page Replacement Algorithm)
– 移位暫存器的大小設定為 0 個位元
– 記憶體中每個頁框均對應到一個參考位元,其初始值為 0;當某分
頁被行程使用時,該參考位元會被設定為 1
– 進行分頁替換時,以先進先出的方式找尋被替換分頁;若找到的
頁框參考位元為 0,則進行替換;若參考位元為 1,則將此分頁的
參考位元設定為 0,給予此分頁第二次機會,不馬上將它替換;並
把此分頁的時間標記設為目前的時間
– 繼續用先進先出的方式找尋被替換分頁,直到所有其它的分頁都
被替換掉,或是都被給予第二次機會之後,該分頁才會被替換掉
– 利用鏈結串列較無效率,可換用環狀佇列方式
第二次機會頁面替換演算法
(The Second Chance Page Replacement Algorithm)
最常參考的頁
最先載入的頁
0
3
7
8
12
14
15
18
A
B
C
D
E
F
G
H
(a)
3
7
8
12
14
15
18
20
B
C
D
E
F
G
H
A
(b)
參考位元 0
參考位元 1
視A如新載入
的分頁
第二次機會頁面替換演算法
(The Second Chance Page Replacement Algorithm)
(The Clock Page Replacement Algorithm)
A
L
B
C
K
J
D
I
E
參考位元 0
F
H
G
參考位元 1
最近最不常使用頁面替換演算法
(The Least Recently Used Page Replacement Algorithm)
• 優先考慮最近不常用的頁面
• 以存取頻率來決策替換的頁面
• 維護一個頁面串列,每次存取必須要把存取頁面移到串列
之首,表示剛剛存取過,維護成本過高,難以硬體實作。
最不常用頁面替換演算法
(The Not Frequently Used Page Replacement Algorithm)
• 與LRU一致,此為軟體實作。
• 每個頁面維護一個計數器,初始為0,每次時鐘中斷,系
統會將存取位元(0 or 1)加到計數器上。
• 計數器有增無減,時間越長會影響到頁面替換演算法決策。
• 頁面老化演算法改進計數器有增無減的狀況,時鐘中斷修
改計數器時,先將計數器右移一位元,把存取位元放入最
左邊的位元上。
Windows記憶體管理概述
• 兩種特權等級
-核心模式(0) 、使用者模式(3)
• 核心模式使用系統位置空間
-0x80000000-0xffffffff
-存取自身行程資料也可以存取系統位置空間
• 使用者模式使用行程位置空間
-0x00000000-0x7fffffff
-只能存取行程自身的資料
Windows記憶體管理概述
• 應用程式使用記憶體必須先申請根據申請和釋放操作來維
護整個虛擬位址空間的記憶體分配情況。
• Windows採用Demand Paging,當一段虛擬記憶體被使用才
為它分配分頁表和實體頁面。
• 每個行程虛擬位址空間的分配透過虛擬位址描述項(Virtual
Address Descriptor)記錄下來,構成一棵平衡二元樹
Page Fault處理步驟
分頁表
作業系統
6.重新執行指令
i
jump func1
move ax,bx
…
2.中斷
1.參考分頁表
3.找尋產生分頁
錯誤的頁
func1:
5.設定分頁表
可用頁框
4.載入產生分頁錯誤的頁
主記憶體
磁碟
Windows記憶體管理概述
• Page Frame Number Database描述實體記憶體每個頁面的狀態。
• Page Directory Entry和Page Table Entry(分頁目錄和分頁表)正確轉
譯虛擬位址。4.3.1
• 位址空間建立後,未獲得實體頁面的虛擬位址時會觸發page
fault例外來分配頁面、設置分頁表和頁面間的邏輯關係。
• 頁面替換由working set manager完成,它執行在一個balance set
manger的系統緒程中。工作集縮減的過程稱為修剪(trim)
Windows記憶體管理重要元件
• 執行體層
-分配、釋放和管理虛擬位置。
• 分頁錯誤例外處理常式(分頁錯誤常式)
-分配實體頁面、磁碟資料讀入頁面。
• 一組系統緒程
-平衡集管理員、行程/堆疊交換器、修改頁面寫出器、零
頁面緒程
4.2 Windows 記憶體管理
995202048 周定緯
系統位址空間
• 在 Intelx86處理器的Windows系統中 ,
0x80000000 - 0xf f f f f f f f 是所有行程共用
的位址空間.
– i.e. , 2GB - 4GB 是系統位址空間
– 在這段位址空間中 , 其配置結構是在核心初始
化階段完成的
系統位址空間初始化
• 在核心獲得控制之前 , Windows 載入程式
( ntldr ) 已經打開了 Intel x86 處理器的分頁
機制 , 並預先建立了足夠的分頁表以便
16MB 以下的低位址可以透過分頁表來存取
其實體記憶體.
ntldr
• Windows 載入程式 (NT loader)
• 程式碼由兩部分組成
– 真實模式 ( 16位元模式 )
– 保護模式 ( 32位元模式 )
ntldr : 真實模式
• 16位元模式
• 執行初始化工作
– e.g. , 清除鍵盤緩衝區
• 為切換到保護模式做好基本的環境準備
• 將控制權交給 OS loader
ntldr : 保護模式
•
•
•
•
32位元模式
預先建構分頁目錄及分頁表來管理實體記憶體
設置分頁目錄暫存器 , 開啟頁面對應機制
執行其他的初始化工作
– e.g. , I/O 裝置初始化
• 載入核心模組
– 預設為 ntoskrnl.exe
• 將核心模組對應到特定的虛擬位址上 , 並將控
制權交給其主函式 KiSysemStartup
WRK 中的元件介面函式字首
區段暫存器
• GDT的設置是在 ntldr 中完成的
– 暫存器 gdtr 的值為 0x 8003f000
– 在 KiSysemStartup 剛獲得控制時 , 其區段暫存器
的值如下 :
區段選擇符格式
區段描述項格式
KiSysemStartup
• CS , DS , ES & SS 區段指向了整個位址空間.
– 0x 00000000 – 0x f f f f f 000
• 幾乎是最大位址 , 差最後一個頁面
– “ 區段 + 偏移 ” 形式的邏輯位址直接直接被對應
成線性位址
• 遮罩了區段機制 , 位址空間平面化
KiSysemStartup
• KiSysemStartup -> KiInitializekernel
– 在啟動處理器 ( P0 ) 上執行全域範圍的核心初始化
• KiInitializekernel -> ExpInitializeExecutive
– 對執行體進行初始化
• ExpInitializeExecutive -> MmInitSystem
– 初始化執行體子元件
• e.g. , 記憶體管理員
– 每個子元件被初始化兩次
• 分別對應於 ” 階段0 “ 以及 “ 階段1 “
核心兩階段初始化
• 由於核心元件之間有緊密的耦合關係 , 所以
他們的初始化不是簡單地循序執行初始化 .
• 階段 0 初始化
– 將階段1初始化需要用到的資料結構建立起來
• 階段 1 初始化
– 核心的完全初始化 , 占據了系統初始化相當一
部分時間
與記憶體管理相關的核心初始化過
程
核心初始化過程
MmInitSystem
• Windows 載入程式 ntldr 只提供了必要的記
憶體環境 , 系統空間主要的初始化工作是在
MmInitSystem 函式中完成的
• MmInitSystem 包含三部分的程式碼邏輯
– 分別對應了 “階段0” , “階段1” 以及 “階段2” 的
初始化
MmInitSystem : 階段 0
• 完成資料結構的初始化以及一些全域變數
的設置 , 例如 :
– MmHighestUserAddress
• 紀錄使用者空間的最高位址 ( 略小於2GB處 )
– MmUserProbeAddress
• 使用者與系統空間的隔離區起始位址 ( size = 64KB )
– MmSystemRangeStart
• 系統空間起始位址 ( 2GB處開始 )
MmInitSystem : 階段 0
• KESEG0_BASE = 0x 80000000
– 系統空間起始位址 = 0x 80000000
• 使用者空間最高位址 = 0x 7 f f e f f f f
• 系統隔離區起始位址 = 0x 7 f f f 0000
– 隔離區大小 = 0x 10000
MmInitSystem : 階段 0
• #define MiGetPteAddress(va)
– ( ( PMMPTE ) ( ( ( ( ( ULONG ) ( va ) ) >> 12 ) << 2 )
+ PTE_BASE ) )
• 給定一個虛擬位址 , 計算出其對應的 PTE 位
址.
– i.e. , 虛擬位址所在頁面的 PTE 位址
• PTE_BASE = 0x c 0000000
MmInitSystem : 階段 0
• #define MiGetPdeAddress(va)
– ( ( PMMPTE ) ( ( ( ( ( ULONG ) ( va ) ) >> 22 ) << 2 )
+ PDE_BASE ) )
• 給定一個虛擬位址 , 計算出其對應的 PDE 位
址.
– i.e. , 虛擬位址所在頁面的 PDE 位址
• PDE_BASE = 0x c 0300000 或 0x c 0600000
– 取決於 PAE ( 實體位址擴充 )
Note
• ntldr 在將控制權交給核心之前 , 已將核心 ,
HAL 和一些啟動的驅動程式對應到
0x800000000 偏上的位置處.
– 在前述記憶體區域劃分好之後 , 這些程式稍後
將被重定到高位記憶體 ( 系統PTE ) 區域.
MmInitSystem : 階段 0
• 設定系統檢視 ( system view ) 大小為 16MB
• 設定工作空間 ( session ) 大小為 48MB
– 0xbd000000 - 0xb f f f f f f f
– 0xc0000000 之上的 48MB
工作階段空間和系統檢視的記憶體
配置結構
MmInitSystem : 階段 0
• 初始化系統快取的位置
– MmSystemCacheStart = 0x c 1000000
– #define MM_SYSTEM_CACHE_END 0x e 1000000
• 分頁集區的變數設置
– MmPagedPoolStart = 0x e1000000
– MmSizeOfPagedPoolInBytes
• 預設 32 MB , 未來會再進行調整
• 計算系統 PTE 數量
– 設定系統全域變數 MmNumberOfSystemPtes
• 介於 7000 – 50000 之間
MmInitSystem : 階段 0
• 初始化與堆積記憶體管理有關的全域變數.
• MmInitSystem -> MiInitMachineDependent
– 此時才真正讓 Windows 的虛擬記憶體運轉起來
– MmInitSystem
• 劃分虛擬位址空間
– MiInitMachineDependent
• 真正建立分頁目錄項目以及分頁表來對應核心各個
區域
MmInitSystem : 階段 0
• 初始化與實體記憶體相關的全域變數
– MmInitSystem -> MmInitializeMemoryLimits
– 獲得有關實體記憶體基本資訊
• 將 ntldr 載入的啟動驅動程式重定到PTE區域
– MmInitSystem -> MiReloadBootLoadedDrivers
– 使得這些程式也能得到 分頁機制的保護
MmInitSystem : 階段 0
• 設置下列全域變數
–
–
–
–
–
–
–
–
MmMaximumDeadKernelStacks
MmModifiedPageMaximum
MmSystemCacheWsMinimum
MmDataClusterSize
MmCodeClusterSize
MmReadClusterSize
MmInPageSupportMinimum
MmFreedExpansionPoolMaximum
• 這些變數用於控制系統空間中一些特殊用途的實體
記憶體頁面的數量 , 或者上下限.
MmInitSystem : 階段 0
• 調整可用實體記憶體頁面的數量
– 調整全域變數 MmResidentAvailable
– 從目前可用頁面數量減掉
• 32個保留頁面
• 非分頁擴充所需要的頁面數
• 系統快取所佔用的最少實體頁面數
MmInitSystem : 階段 0
• 建立系統快取結構
– 系統快取結構位址
• MmSystemCacheWorkingSetList = 0x c0c00000
– 系統快取位址
• MmSystemCacheStart = 0x c1000000
– 系統快取最大可能位址 = 0x e1000000
• 取決於 MaximumSystemCacheSize 的變化情況
– MmInitSystem -> MiInitializeSystemCache
• 初始化快取系統工作集 , 並建立相關管理資料結構
MmInitSystem : 階段 0
• 設置全域變數 MmTotalCommitLimit
– 代表最多可提交的記憶體數量 , 及最多可以兌
現多少實體記憶體
– MmTotalCommitLimitMaximum =
MmTotalCommitLimit
• MmMaximumWorkingSetSize
– = “總可用頁面數” - 512
MmInitSystem : 階段 0
• MmInitSystem -> MiBuildPagedPool
– 建立分頁集區
• MmInitSystem-> MiInitializeLoadedModuleList
– 初始化已載入的模組表 , 將這些模組對應到系
統空間中
• 階段0初始化
翁志嘉
MiInitMachineDependent ( )
//建立當前process的頁目錄
PointerPte = MiGetPdeAddress (PDE_BASE);
//得到process 對應的PDE位址
PdePageNumber = MI_GET_PAGE_FRAME_FROM_PTE(PointerPte);
//得到PoiterPte 所指到的 PDE有多少個page
CurrentProcess = PsGetCurrentProcess (); // 得到指向EProcess的pointer值
DirBase = MI_GET_PAGE_FRAME_FROM_PTE (PointerPte) << PAGE_SHIFT;
//PAGE_SHIFT=12,得到DirBase的位址
CurrentProcess->Pcb.DirectoryTableBase[0] = DirBase;
//把得到的DirBase值存於的位址CurrentProcess的PCB中
KeSweepDcache (FALSE); // Do nothing
i386.h 程式碼片段
•
•
•
•
•
•
•
•
•
•
•
•
•
•
•
•
•
#define PDE_BASE_X86 0xc0300000
#define PDE_BASE_X86PAE 0xc0600000
#define PTE_TOP_X86 0xC03FFFFF
#define PDE_TOP_X86 0xC0300FFF
#define PTE_TOP_X86PAE 0xC07FFFFF
#define PDE_TOP_X86PAE 0xC0603FFF
#if !defined (_X86PAE_)
//CPU支援PAE (Physical Address Extension)或者開啟了PAE
#define PDE_BASE PDE_BASE_X86 // i386.h 1964行
#define PTE_TOP PTE_TOP_X86
#define PDE_TOP PDE_TOP_X86
#else
#define PDE_BASE PDE_BASE_X86PAE // i386.h 1968行
#define PTE_TOP PTE_TOP_X86PAE
#define PDE_TOP PDE_TOP_X86PAE
#endif
#define PTE_BASE 0xc0000000
PointerPte = MiGetPdeAddress (PDE_BASE);
#define MiGetPdeAddress(va) ((PMMPTE)(((((ULONG)(va))
& >> 22) << 2) + PDE_BASE))
//作用是通過一個虛擬地址va,得到其對應的pde地址。先右移
22位元,取得線性位址的最高10位,再左移2位,加上頁目
錄的開始位址,得到PDE的位址。
PDE_BASE = 0xc0300000
(11000000 00110000 00000000 00000000)
PointerPte = 0xc0300c00
(11000000 00000000 00001100 00000000)
MI_GET_PAGE_FRAME_FROM_PTE
(mi386.h 2542行 )
#define MI_GET_PAGE_FRAME_FROM_PTE(PTE) ((PTE)>u.Hard.PageFrameNumber)
//
// Unmap the low 2Gb of memory.
//
PointerPde = MiGetPdeAddress (0);
LastPte = MiGetPdeAddress (KSEG0_BASE);
MiZeroMemoryPte (PointerPde, LastPte - PointerPde);
//將分頁目錄表(PDE)中對應0~2GB (使用者記憶體空間)
//之間分頁目錄寫成0,意味目前Process不使用這部分空間。
ntldr會傳遞關於實體記憶體的描述串列,如下:
typedef struct _LOADER_PARAMETER_BLOCK {
LIST_ENTRY LoadOrderListHead;
LIST_ENTRY MemoryDescriptorListHead;
//透過此依資訊,求得實體記憶體page的數量,以及空閒記憶體的最低位址
LIST_ENTRY BootDriverListHead;
ULONG_PTR KernelStack;
……
*SetupLoaderBlock;
PLOADER_PARAMETER_EXTENSION Extension;
} LOADER_PARAMETER_BLOCK,
*PLOADER_PARAMETER_BLOCK;
透過MemoryDescriptorListHead可以得到全域變數
MmNumberOfPhysicalPages (實體記憶體page的數量)
以及 MmHighestPossiblePhysicalPage(空閒記憶體的最低位址)
接著設置MmDynamicPfn(最高可用的實體位址頁編號)
以及MmHighestPossiblePhysicalPage(最高可能的實體頁面)
然後調整MmSizeOfNonPagedPoolInBytes (非分頁集區的大小)
以及MmMaximumNonPagedPoolInBytes(非分頁集區的最大尺寸)
接下來的就是計算PFN資料庫(Page Frame Number DataBase)和非換頁池
(NonPagedPool)的大小,然後開始分配系統PTE和擴展的非換頁池的頁表
StartPde = MiGetPdeAddress (MmNonPagedSystemStart);
//獲得系統Non Paged的開始目錄項位址
EndPde = MiGetPdeAddress ((PVOID)((PCHAR)MmNonPagedPoolEnd - 1));
//獲得系統Non Paged的結束目錄項位址
while (StartPde <= EndPde)
{
ASSERT (StartPde->u.Hard.Valid == 0);
TempPde.u.Hard.PageFrameNumber = MxGetNextPage (1, TRUE);
// MxGetNextPage分配一個實體頁,並傳回其page number 給虛擬頁
*StartPde = TempPde;
//將TempPde指定給StartPde,亦即再分頁目錄中加入一個PDE
PointerPte = MiGetVirtualAddressMappedByPte (StartPde);
//反推,得到StartPde的Page Table所在的虛擬記憶體
//#define MiGetVirtualAddressMappedByPte(PTE) ((PVOID)((ULONG)(PTE) << 10))
RtlZeroMemory (PointerPte, PAGE_SIZE);
//初始化此page table,全部填0
StartPde += 1;
}
Windows 的分頁目錄自對應方案
虛擬記憶體共有32位元
頁目錄索引(10bit) 分頁表索引(10bit) 偏位移量(12bit)
每個頁目錄索引以及分頁目錄索引均為4bytes,因此需要4k
的頁目錄和4M的頁表,
windows將頁表安排在0xc0000000~0xc0400000,
頁目錄安排在0xc0300000~0xc0400000。
Windows 的分頁目錄自對應指的是頁目錄項本身也會用作頁
表項, 其優點是讓PDE及PTE能夠根據他們自己的虛擬位址
推匯出所指向的實體頁面的虛擬位址
Windows 的分頁目錄自對應方案 (續)
若PDE位址為0xc0300000
11000000 00110000 00000000 00000000
將PDE左移10位得到 0xc0000000
11000000 00000000 00000000 00000000
若PDE位址為0xc0300c00
11000000 00110000 00001100 00000000
將PDE左移10位得到 0xc0300000
11000000 00110000 00000000 00000000
在此,我們可以清楚看出,當PDE=0xc0300c00時,所有的分頁
表會位於0xc0300000~0xc0400000之間,也因如此,構成了分頁
目錄自對應方案的優點。
PFN資料庫與非分頁集區管理
• Windows在系統位址空間高位處保留了一塊位址範圍用做系統當機時的資
訊轉存區域,並為其分配了一個頁表,其起始位址為0xffbe0000,大小不
超過4 MB。
• MiInitializeNonPagedPool( )
//建立非換頁記憶體池的管理結構
• MiInitializeNonPagedPoolThresholds( )
//設定非換頁記憶體池的高、低閾值
• 然後分配PFN所需的實體頁,範圍從FirstPfnDatabasePage開始,總共
MxPfnAllocation個頁面。
• 根據系統載入程式傳遞過來的實體記憶體描述項串列,檢查所有的記憶體
描述項,並把可用的記憶體都加入到PFN資料庫的空閒串列。
PFN資料庫與非分頁集區管理 (續)
• 接下來掃描PFN資料庫所用到的PTE,並把它們對應的頁面標記為已經在
使用 。
• 呼叫InitializePool ( )初始化非分頁集區。至此,非分頁集區以建立起來並
可以使用。
• 透過MiInitializeSystemPtes( )對系統的PTE進行初始化。
• 接著初始化目前process的記憶體管理結構,並建立起工作集串列,包含建
立一個PDE,以及初始化該PDE所指的page table。
• 最後,將管理記憶體所需的實體頁面標記為已在使用,至此,
MiInitMachineDependent 函式完成其初始化工作。
• 階段1初始化
• 階段2初始化
• 系統位址空間記憶體管理
– 系統非分頁集區的管理演算法
995202031 秦承鴻
分頁表是否已分配|頁面是否已分配
0x80000000
MmPfnDatabase
MmNonPagedPoolStart
MiSystemCacheStartExtra
MiMaximumSystem
CacheSizeExtra(個
頁面)
MiSystemViewStart
MmSeesionBase
0xc0000000
0xc0400000
MmSystemCacheWorkingS
etList
MmSystemCacheStart
MmPagedPoolStart
MmNonPagedSystemStart
MmNonPagedExpansionSt
art
0xffbe0000
核心、HAL等系統模組
的映象區
PFN 資料庫
非分頁集區
系統快取額外區
系統PTE額外區
系統檢視
工作階段空間
分頁表
超空間和行程工作集
系統快取結構
系統快取
分頁集區
系統PTE區域
非分頁集區擴充區
當機轉存區
0xffffffff
保留區
部分
全域變數名
典型取值
全域變數名
典型取值
MmHighestUserAddress
0x7ffeffff
MiSessionImageStart
0xbf800000
MmUserProbeArresss
0x7fff0000
MiSessionImageEnd
0xc0000000
MmSystemRangeStart
0x80000000
MmSystemPteBase
0xc0000000
MmPfnDatabase
0x81000000
MmWorkingSetList
0xc0502000
MmNonPagedPoolStart
0x81301000
MmHyperSpaceEnd
0xc0bfffff
MmNonPagedPoolEnd0
0x82000000
MmSystemCacheWorkingSetList
0xc0c00000
MiSystemCacheSizeExtra
0x82000000
MmSystemCacheStart
0xc1000000
MiMaximumSystemCacheSizeExtra
0x2f800
MmpagedPoolStart
0xc1000000
MiSystemViewStart
0xbb000000
MmpagedPoolEnd
0xf0bfffff
MmSessionBAse
0xbc000000
MmNonPagedSystemStart
0xf0c00000
MmSessionPoolStart
0xbc000000
MmNonPagedPoolExpansionStart
0xf8ba0000
MiSessionViewStart
0xbc400000
MmNonPagedPoolEnd
0xffbe0000
MisessionSpaceWs
0xbf400000
MmNumberOfPhysicalPages
0x0001ff7a
階段1初始化
階段1:
MmInitSystem
1
2
3
4
MiInitMachineDependent
MiMapBBTMemory
MiSectionInitialization
申請PTE物件
如果處理器支援大頁面,並且在前面
初始化過程中有紀錄下來要轉換成大
頁面的記憶體區域,則把這些區域轉
換成大頁面對應。
為BBT預留一塊記憶體緩衝區。由於
在預設配置下,BBTPagesToReserve
為 0,所以此函式什麼都不做。
建立
記憶體區段物件型別,建立區段
提領系統執行緒,並且建立記憶體區
段物件
,再插入到目前行程控制碼表
將MmSharedUserDataPte指向此PTE物
中。
件,該PTE紀錄使用者共用資料頁的
PTE,位於0xffdf0000。接下來把該
PTE指定到行程位址空間的0x7ffe0000
所對應的PTE中。
階段1初始化
初始化階段空間。
階段1:
MmInitSystem
5
6
7
8
9
10
MiSessionWideInitializeAddress
MiInitializeSessionWsSupport
MiInitializeSessionIds
建立修改頁面寫出器(modified
page writer)的系統執行緒。
初始化系統記憶體事件,包括高記憶
體和低記憶體事件,以及分頁集區和
非分頁集區的高低事件。
兩個系統緒程,分別為
KeBalanceSetManger和
KeSwapProcessOrStack函式。
MiInitializeMemoryEvents
啟動零化頁面的系統輔助執行緒。
啟動平衡集管理員
MiStartZeroPageWorkers
對所有已經載入的模組設置其保護
屬性。
MiWriteProtectSystemImage
至此,階段1初始化完成,全域變數MiFullyInitialized設置為 1。
階段2初始化
• MmInitSystem只有呼叫MiEnablePagingTheExecutive函式,
將目前已載入的模組中的可分頁程式碼區變成可分頁的,
它找到每個模組的 PAGE 記憶體區,然後呼叫
MiEnablePagingOfDriverAtInit函式以改變相關PTE中的標
記。
– 讓可分頁程式碼區的PTE可以在記憶體吃緊的情況下騰出實體
記憶體頁面
• 記憶體管理員的初始化工作全部完成,而且系統空間已
經完全建立起來。
總結
階段0初始化
1.劃分系統位址空間,它充分可慮到實體記憶體
的數量和啟動選項指定的要求,使得最終得到的
各部分區域的範圍相對比較合理。
2.負責建立起分頁目錄和分頁表結構,並且完成
非分頁區域的實體頁面分配。
階段1初始化
記憶體管理工作的初始化,包括建立修改寫出器
和平衡集管理員,以及零化頁面工作。
階段2初始化
只是簡單地使系統模組中的分頁程式碼區可被分
頁而已。
系統位址空間記憶體管理
• 在系統位址空間中,有些部分是供一些特殊模組
使用的,比如工作階段空間是由工作階段管理員
和Windows子系統使用的;而分頁集區和非分頁
集區則是提供給系統核心模組和裝置驅動程式使
用的。
• 在分頁集區中分配的記憶體有可能在實體記憶體
吃緊的情況下被換出到外部記憶體;而非分頁集
區中分配的記憶體總是處於實體記憶體中。
系統位址空間記憶體管理
執行體記憶體集區
(非分頁)
系統非分頁集區
非分頁集區擴充
區域
執行體記憶體集區
(分頁)
系統分頁集區
Windows核心中的動態記憶體管理結構
系統PTE區域
系統非分頁集區的管理演算法
• MiInitializeNonPagedPool的主要任務是初始化用於
管理記憶體集區的一些全域變數,尤其是,用於
存放空閒頁面串列開頭的
MmNonPagedPoolFreeListHead陣列。
• 空閒頁面串列中的每一項是一個
MMFREE_POOL_ENTRY結構
typedef struct _MMFREE_POOL_ENTRY{
LIST_ENTRY List;
PFN_NUMBER Size;
ULONG
Signature;
struct _MMFREE_POOL_ENTRY *Owner;
} MMFREE_POOL_ENTRY , *PMMFREE_PPOL_ENTRY;
系統非分頁集區的管理演算法
• 非分頁集區有兩部分:
– 基本記憶體集區:其中所有頁面都已經分配了實體頁
面
– 擴充記憶體集區:只有當基本區無法滿足記憶體申請
需求時才會分配真正的實體頁面
• 由於非分頁集區的空閒頁面已經被對應到實體頁
面,所以Windows充分利用這些頁面自身的記憶
體來建構起一組空閒頁面串列。
List
Size
Sign
Owner
Owner
Owner
List
Owner
Size
Sign
Owner
>=4頁面空閒串列
List
Size
Sign
Owner
Owner
List
Owner
Size
Sign
Owner
3頁面空閒串列
List
Size
Sign
Owner
Owner
List
Size
Sign
Owner
雙頁面空閒串列
List
Size
3 2 1 0
空閒串列陣列:
MmNonPagedPoolFreeListHead
Sign
Owner
單頁面空閒串列
List
Size
Sign
Owner
系統非分頁集區的管理演算法
• 對於已經確定的SizeInPages個頁面,
MiAllocatePoolPages函式分別找到其起始頁面和結
束頁面在PFN資料庫中的紀錄,並且分別設置它們
的StartOfAllocation和EndOfAllocation位元。
• 如果在空閒串列陣列中搜尋不到滿足條件的空閒
節點,則MiAllocatePoolPages函式試圖擴充非分頁
集區,並滿足所要求的頁面數。
系統非分頁集區的管理演算法
• MiFreePoolPages
– 對於一個給定的起始位址StartingAddress,找到它的PTE,並
提取出PFN,從而找到PFN資料庫中起始頁面的PFN項目
– 凡是透過MiAllocatePoolPages分配得到的連續頁面,其首頁
面的PFN項目的StartOfAllocation位元必定是1,沿著此PFN項
目進行搜尋,可以找到結束頁面,其PFN項目的
EndOfAllocation位元為 1
• 為了維護非分頁集區中的空閒串列結構,被回收的頁
面如果有可能的話,還要跟它們後續的空閒頁面或者
它們前面的空閒頁面合併成一個更大的空閒區塊。
系統非分頁集區的管理演算法
• 如果StartingAddress指示了一個非分頁擴充集區中
的位址,則可能有必要呼叫MiFreeNonPagedPool
函式來回收他的頁面。
系統非分頁集區的管理演算法
• 在收回單個頁面的時候,如果MiFreePoolPages 函
式發現,MiNonPagedPoolSListHead 串列中的頁
面數小於MiNonPagedPoolSListMaximum,
則將此頁面加入到MiNonPagedPoolSListHead 串列
中。
• 因此,在MiAllocatePoolPages的開始處,如果使用
者要申請單個頁面,並且
MiNonPagedPoolSListHead串列不為空的話,則直
接從串列開頭提取一個頁面回傳給使用者。
Windows 核心原理實務開發
系統分頁集區的管理演算法
995402004
謝正達
• 不合適使用非分頁集區的空閒頁面串列作法
– 分頁集區中的空閒頁面不保證有對應的實體頁面
– 出於管理的原因而為分頁集區的空閒頁面分配實體頁
面,不符合分頁集區的設計目的
typedef struct _MM_PAGED_POOL_INFO{
PRTL_BITMAP PagedPoolAllocationMap;
PRTL_BITMAP EndOfPagedPoolBitmap;
PMMPTE FirstPteForPagedPool;
PMMPTE LastPteForPagedPool;
PMMPTE NextPdeForPagedPoolExpansion;
ULONG PagedPoolHint;
SIZE_T PagedPoolCommit;
SIZE_T AllocatedPagedPool;
}MM_PAGED_POOL_INFO, *PMM_PAGED_POOL_INFO;
PagedPoolAllo
cationMap
EndOfPagedPo
olBitmap
FirstPteForPagedPool
LastPteForPagedPool
PagedPoolHint
PagedPoolCommit
AllocatedPagedPool
MM_PAGED_POOL_INFO
MM_PAGED_POOL_INFO
NextPdeForPagedPoolExpansion
• 全域分頁集區
– MmPagedPoolInfo
• 工作階段空間
– MmSessionSpace.PagedPoolInfo
• 分頁集區啟始位址
– 系統全域範圍
• MnPagedPoolStart(變數)
– 工作階段空間
• MiSessionPoolStart(變數)
• 透過點陣圖(bitmap)管理分頁集區
– 一個頁面的分配與否,由該頁面所對應的位元來表達
– PagedPoolAllocationMap
• 用以指明每一個頁面的分配狀態
– EndOfPagedPoolBitmap
• 標明每個頁面是否為一次記憶體申請的最後一個頁面
– FirstPteForPagedPool
– LastPteForPagedPool
•
規定記憶體集區的位址範圍
– NextPdeForPagedPoolExpansion
• 定義分頁集區下次的擴充位置
– PagedPoolCommit
• 記錄有多少個頁面已經分到了記憶體
– AllocatedPagedPool
• 記錄分頁集區分配到了多少頁面
– PagedPoolHint
• 分配頁面時的起始搜尋位置
環境變數
• MnInitSystem
– 呼叫MiBuildPagedPool建立系統的分頁集區大小
– MiBuildPagedPool用於初始化MnPagedPoolInfo
的所有成員
– MnSizeOfPagedPoolInBytes
– MnSizeOfPagedPoolInPages
• 記錄分頁集區的大小
• 最大不超過MnNonPagedSystemStartMnPagedPoolStart
• MmPagedPoolStart
• MmPagedPoolEnd
– 分別紀錄分頁集區的起始位址與結束位址
– MmPagedPoolInfo中的FirstPteForPagedPool與
LastPteForPagedPool可根據這兩變數的值直接匯
出
初始化
• 呼叫MiBuildPagedPool分配好一個分頁表,
即起始位置的PDE
• NextPdeForPagedPoolExpansion即為接下來
的分頁表位址
• 呼叫MiCreateBitMap函式建立BitMap
– 非分頁集區分配
– PagedPoolAllocationMap(1024 bits)設為0
– EndOfPagedPoolBitmap相同初始化為0
• MiBuildPagedPool呼叫InitializePool初始化執行
體分頁集區
• 設置預警閥值
– MiLowPagedPoolThreshold
– MiHighPagedPoolThreshold
• 如果系統禁止執行體記憶體集區分頁,即全域
變數MmDisablePagingExecutive中的
MM_PAGED_POOL_LOCKED_DOWN旗標將被設
定
– 分頁集區被設定成非分頁集區
分頁配置與釋放
• MiAllocatePoolPages
– PoolType決定在那個記憶體集區中申請頁面
• MiFreePoolPages
• 分配過程
– 根據PoolType找到對應的記憶體集區
MM_PAGED_POOL_INFO結構
– 呼叫RtlFindClearBitsAndSet找尋
PagedPoolAllocationMap中連結零位元,如果無
法找到,則設法擴充分頁集區
(NextPdeForPagedPoolExpansion後移)再重新呼
叫RtlFindClearBitsAndSet
• MiAllocatePoolPages函式,更新
PagedPoolInfo中已分配頁面的數量
– AllocatedPagedPool欄位
– 如果數量小於MiLowPagedPoolThreshold則發出
預警訊號(MiLowPagedPoolEvent)
– 檢查這些頁面是否需要刷新他們的 TLB
• 是呼叫KeFlushSingleTB, KeFlushMultipleTB,
KeFlushEntireTB函式刷新TLB
• 呼叫MiFreePoolPages回收頁面
– 傳入的StartingAddress介於MmPagedPoolStart和
MmPagedPoolEnd之間,說明這是系統分頁集區
的頁面
– 利用PagedPoolInfo中的兩個BitMap驗證位址的
有效性,並修改BitMap與更新
AllocatedPagedPool和PagedPoolCommit欄位
• MiFreePoolPages幾項說明
– 如果被分配為非分頁集區,則只需要維護BitMap與
相關的全域變數與記憶體區變數
– 如果是單個頁面被釋放,則有可能加入到一個單串
列中。單串列由MiPagedPoolSListHead記錄,本串
列最多記錄8個單頁面,如果下次需要申請單頁面,
則MiAllocatedPoolPages,直接從該串列提取
– 遵從系統分頁集區的管理
• MiChargeCommitmentCanExpand函數
• MiReturnCommitment函式
• MiDeleteSystemPageableVm函式