Windows 記憶體管理

123
Windows 記記 記記 記5記

description

Windows 記憶體管理. 第 5 組. 記憶體管理概述 分頁式記憶體 管理 徐勝斌. 4.1 記憶體管理概述. 在 Intel x86 系統架構中,記憶體位址有三種類型: 實體位址 即記憶體儲存器的索引,當 CPU 操縱記憶體晶片時,它透過位址線腳位價上電子信號來讀取或寫入相關的記憶體單元。 虛擬位址 ( 又稱線性位址 ) 在邏輯位址轉換為實體位址的過程中,會先產生對應的虛擬位址。之後遵循分頁的機制,再由虛擬位址產生實體位址。 邏輯位址 由 CPU 所產生的位址,稱為邏輯位址 (logical address) 。 - PowerPoint PPT Presentation

Transcript of Windows 記憶體管理

Page 1: Windows  記憶體管理

Windows 記憶體管理第 5 組

Page 2: Windows  記憶體管理

• 記憶體管理概述– 分頁式記憶體管理

– 徐勝斌

Page 3: Windows  記憶體管理

4.1 記憶體管理概述• 在 Intel x86 系統架構中,記憶體位址有三種類型:

– 實體位址• 即記憶體儲存器的索引,當 CPU 操縱記憶體晶片時,它透過位址線腳位價上電子信號來讀取或寫入相關的記憶體單元。

– 虛擬位址 ( 又稱線性位址 )• 在邏輯位址轉換為實體位址的過程中,會先產生對應的虛擬位址。之後遵循分頁的機制,再由虛擬位址產生實體位址。

– 邏輯位址• 由 CPU 所產生的位址,稱為邏輯位址 (logical address) 。 • 要執行時,程式的這些部分在經過一些必要的處理之後,會變成對記憶體有意義的位址值。

Memory

CPU +

Base Register

Logical Address

Physical Address

0004

1000

1004

Page 4: Windows  記憶體管理

4.1 記憶體管理概述• 把一個位址告訴 CPU ,讓它存取相對應的實體記憶體單元,這一過程是 OS 和 CPU 相互合作來完成的。

– CPU 最終需要的是一個實體位址,所以他必須把軟體指令中的位址轉譯成實體位址– 從 OS 的角度來看,需要有效的管理實體記憶體,使 Process需要記憶體時,可以分配足夠的記憶體給這個 Process– 每個 Process 有邏輯上獨立的位址空間,不同 Process 的位址空間應該是相互隔離的

• 在一個 Process 1 使用位址 A 來存取一個記憶體單元,與另外一個Process 2 中用位址 A 存取的記憶體單元是不同的實體記憶體,這樣只可以避免有意或無意的侵入到另外一個 Process 的位址空間中。

Page 5: Windows  記憶體管理

4.1 記憶體管理概述• 虛擬記憶體 (Virtual Memory)

– 當系統中 Process 數量增加時,所需的記憶體數量往往超過了總實體記憶體– 一般的做法是把不緊急的 Process 中的資料或程式碼先存放到外部記憶體,而把它們佔用的實體記憶體騰出來給緊急

Process 使用– 好處:

• 允許 Program Size 大於 Physical Memory Size 仍能執行• 程式撰寫者專心負責寫好程式,無須考量 Program Size 太大之問題• Memory utilization 提升

DiskSWAP out

SWAP in

Memory

Page 6: Windows  記憶體管理

4.1.1 分頁式記憶體管理• 在分頁式記憶體管理中,虛擬位址空間是按頁 (page)來管理的,對應於實體記憶體也是按照頁 (page) 來管理,實體記憶體中的頁面有時後稱為分頁框架 (page

frame)– 在虛擬位址空間中連續的頁面對應於實體記憶體中的頁面可以不必是連續的– 實體頁面可以被動態地分配給特定的虛擬頁面

虛擬位址空間 實體位址空間

虛擬頁面與實體頁面之間的對應

Page 7: Windows  記憶體管理

4.1.1 分頁式記憶體管理• 動態變動分區之 Memory Management

– 在 Multi programming 之下,系統 (Memory) 內存在有多個 Process執行,而且各個 Process 之大小並不相同,進入系統及完成工作的時間也不盡相同– 若採” Contiguous Allocation” ,即系統要分配給 Process 夠大的連續可用空間, Process 才能載入執行

• “Extended Fragmentation” Problem :沒有足夠大的連續性空間可以配置給 Process 使用• “Internal Fragmentation” Problem :配置給 Process 的 Memory 空間大於 Process 實際所需空間

Process 1

Process 5

Process 6

150 K

300 K

Memory

FreeAllocated

Process OS 配置的Memory

Space

實際Process所佔空間 內部碎裂 (Internal Fragmentation)

Page 8: Windows  記憶體管理

4.1.1 分頁式記憶體管理• 有了頁面 (page) 劃分機制後,每個虛擬位址 32 位元資訊中分成兩部分:頁索引 + 頁內偏移

– 根據頁索引去查 Page Table ,取得該 Page 之對應載入頁框之起始為址 + 頁偏移量即得 Physical Address.

Page # Page offset

虛擬位址

Page table012

f2f4f5

f0f1f2f3f4f5

Memory

+

會有 Internal Fragmentation 問題,因為 user program size 不見得是Page size 的整數倍eq: page size = 4KB process size = 21 KB => 須配 6 個 Frame => 內部碎裂 : 24 – 21 = 3 KB

Page 9: Windows  記憶體管理

4.1.1 分頁式記憶體管理• Intel x86 採用分級分頁表的方式來管理

– 32 位元的虛擬位址頁索引被分為頁目錄索引 (10 位元 ) 和分頁表索引 (10位元 )– 分頁目錄項目 (PDE, Page Directory Entry) : 210 = 1024 項的分頁表– 分頁表項目 (PTE, Page Table Entry) : 210 = 1024 項的頁面

分頁目錄索引 分頁表索引 頁內偏移01112212231

分頁目錄 (PDE)

分頁表 (PTE)

頁面1. 二級分頁表結構好處是,當虛擬位址空間中實際使用的記憶體比例較小時,很多分頁表不必在記憶體中建構出來2. 要付出效能的代價,在解析一個虛擬位址時,需要兩次查表動作

Page 10: Windows  記憶體管理

4.1.1 分頁式記憶體管理• 位址轉譯快查緩衝區 (TLB, Translation Look-aside Buffer)

– 為了避免在分級分頁表解析過程中多次查表導致效能下降問題– 包含最近使用過的頁面的記憶體對應資訊– 在 Intel x86 處理器中, TLB 是完全由硬體來維護的

1. 到 TLB 查詢有無對應的Page Number 存在

2. 若 Hit, 則輸出 Frame 起始位址3. 若 Miss,則到 Memory 中取 出 Page Table 查詢,已取得 Frame 起始位址

Page 11: Windows  記憶體管理

4.1.1 分頁式記憶體管理• 實體位址擴充 (PAE, Physical Address Extension)

– 支援 36 位元實體位址,即 64GB 實體記憶體– 但虛擬位址仍然是 32 位元– 分頁目錄和分頁表中的每一項為 64 位元,可以描述更長的實體位址

Page 12: Windows  記憶體管理

• 區段式記憶體管理

985402024 黃郁誠

Page 13: Windows  記憶體管理

除了用虛擬位址來實作有效和靈活的記憶體管理以外另一種記憶體管理方式是將實體記憶體劃分成若干個區段 (segment).

計算實體記憶體位址方式: “ 區段基址 + 偏移”每個區段可以有它自己的存取屬性, 包括讀寫屬性、特權等級等。例如, Intel x86 的處理器中,有專門的區段暫存器,允許每行指令在存取記憶體時,指定在哪個區段上進行。

4.1.2 區段式記憶體管理

Page 14: Windows  記憶體管理

14

區段概念在 Intel 8086/8088 真實模式中已經使用了,但當時區段的用途是擴充位址範圍,將系統的記憶體從 64K擴充到 1MB 。Intel 8086/8088都是 16 位元的,但位址線有 20條。為了存取整個位址範圍,處理器的作法,將區段暫存器中的值左移 4 位元再加上一個 16 位元址值。最大的位址值: (64K-1)*16+(64K-1) = 1,114,095BIntel 80286 (24 位元位址 ) ,在保護模式下:區段變成一個索引:指向段描述項表中的某一個段描述項,而段描述項才真正指定了區段的基底位址、區段長度以及一些保護屬性。Intel 80386 以後,處理器中的暫存器才真正轉移到 32 位元

4.1.2 區段式記憶體管理

Page 15: Windows  記憶體管理

15

Intel x86 中,邏輯位址的區段部分稱為區段選擇符 (segment selector) ,指定了區段的索引以及要存取的特權等級。區段暫存器 cs、 ss、 ds、 es、 fs 和 gs 專門用於指定一個位址的區段選擇符,其中有三個區段暫存器有特殊的用途。cs : 程式暫存器,指向一個包括指令的區段。ss :堆疊段暫存器,指向一個包含目前呼叫推疊的區段。ds : 資料區段暫存器,指向一個包含全域和靜態資料的區段。

4.1.2 區段式記憶體管理

Page 16: Windows  記憶體管理

16

區段索引 表指示位址 目前特權等級

15 3 2 1 0

雖然定指暫存器和資料暫存器都是 32 位元,但是區段選擇只有 16 位元,如下圖所示:

一個段描述項表只包含213=8192 的區段 GDT or LDT

GDT : 全域段描述項表LDT : 區域區段描述項表

請求者的目前特權等級 (0~3)

4.1.2 區段式記憶體管理

區段選擇符格式

Page 17: Windows  記憶體管理

4.1.2 區段式記憶體管理段描述項表格式 :

區段內最大偏移 (16-19)

未使用 ( 作業系統可使用 )

區段偏移位址 32 位元 (1) 或 1 位元 (0)

粒度標誌,最大偏移欄位位元組(0)頁面 (1) 單位

S : 0 表示系統區段 1 表示普通區段DPL :描述項套全等級

17

區段內最大偏移 (0-15)

基底位址 (0-15)

1 DPL S 類型 基底位址 (16-23)

基底位址 (24-31) GD/B 0

Page 18: Windows  記憶體管理

18

4.1.2 區段式記憶體管理G :當 G = 0 ,指長度單位為位元組 G = 1 時,長度單位為 4096 位元組 區段長度可以達到 220*4096 = 4GB = 整個 32 位元線性位址 空間。DPL :允許存取此區段的最低特權等級,例如, DPL 為 0 的區段只能當 CPL=0 時才可以存取。 DPL 為 3 個區段可由任何 CPL 的程式碼存取。類型:指定了區段的類型,包括程式段、資料段、 TSS 區段 和 LDT 區段。

Page 19: Windows  記憶體管理

19

4.1.2 區段式記憶體管理GDT 和 LDT

GDT︰系統全域範圍內有效的一張表,包含最多 8192 的段描述項,所以一張表需要 8192*8 =64KB 記憶體空間

Page 20: Windows  記憶體管理

20

4.1.2 區段式記憶體管理

區段索引 表指示位址 目前特權等級

0

1

GDT

LDT

gdtr

ldtr

區段基底位址

區段基底位址

線性位址(32 位元 )

偏 移 (32 位元 )

Intel x86 “ 區段 + 偏移” 形式的邏輯位址的解析過程

Page 21: Windows  記憶體管理

21

4.1.2 區段式記憶體管理系統全域共同的空間可以透過 GDT 來安排案存取。此外,每個行程私有的資料和程式碼存放在 LDT 中,因而行程切換時,只需改變 LDT 表,就實作了行程私有位址的切換。區段式記憶體管理和分頁式記憶體管理並不是對立的,它們可以組合起來在同一個系統使用。

區段式記憶體管理單元 分頁式記憶體管理單元“ 區段基址 + 偏移” 虛擬位址 實體位址

Intel x86 邏輯位址個完整解析過程

Page 22: Windows  記憶體管理

22

4.1.3 記憶體管理演算法介紹記憶體管理演算法分為兩類: 點陣圖標記法:假設整個待分配記憶體的大小為 N 位元組,管理記憶體的粒度為 M 位元組,並且 N=M*K ,也就是說,記憶體管理的基本單元為 M 位元組,現在共有 K 個單元需要動態管理。 為了記錄這 K 個記憶體管理單元的使用情況,點陣圖標記法是用一個共有 K 個位元的點陣圖,其中每一位元的值(0 或 1)說明了這一位元所對應的記憶體單元是否空閒。 由於點陣圖精確地記錄了每一個記憶體單元的空閒或已被使用的情況,所以,當記憶體管理員接收到一個新的記憶體申請時,他只需掃描點陣圖,就能確定是否有合適的空閒記憶體可以滿足請求。

Page 23: Windows  記憶體管理

23

4.1.3 記憶體管理演算法介紹點陣圖標技法的實作需要額外的記憶體負擔,通常為所以,只需適當地選取 M ,就可以控制這部分額外的負擔。使用者請求記憶體大小不一定是 M 位元組的倍數,因而在分配記憶體時,平均為M/2 位元組的浪費。記憶體管理員在分配記憶體時需要掃描連續個 0 位元,此操作並不高效率 (複雜度 O(K))

8*NN

Page 24: Windows  記憶體管理

24

4.1.3 記憶體管理演算法介紹空閒串列法:使用串列來描述已分配的空閒塊。初始時,整個區塊被當作一個大的空閒區塊加入到空閒串列中。當記憶體管理元接收到一個記憶體分配請求時,從空閒串列中找到一個合適的、能提供足夠記憶體的空閒區塊,並且從該空閒區塊中分離出足夠多的記憶體,交給客戶,剩下的記憶體仍然是一個空閒區塊,而且分配的記憶體加入到已分配記憶體串列中。

Page 25: Windows  記憶體管理

25

4.1.3 記憶體管理演算法介紹當記憶體管理元接收到一個記憶體分配請求時,會使用不同的測略來搜尋適當的空閒區塊 :

1. 先適法 (first-fit): 從空閒串列中找到第一個滿足客戶請求的空閒區塊。2. 佳適法 (best-fit): 從空閒串列中找到最接近於客戶請求大小的空閒區塊。 3. 差適法 (worst-fit): 從空閒串列中找到最大的空閒區塊。4. 次適法 (next-fit): 從空閒串列的目前位置往後掃描,找到第一個滿足客戶 請求的空閒區塊。

Page 26: Windows  記憶體管理

頁面替換演算法Page Replacement Algorithms

985402001 索維廷

Page 27: Windows  記憶體管理

按需分頁 (demand paging)• 行程所需資料最初所有頁面都在磁碟上• 隨著控制流不斷前進,行程獲得越來越多實體記憶體頁面,趨向平滑• 記憶體頁面的請求和滿足透過中斷或例外的方式來完成

Page 28: Windows  記憶體管理

按需分頁 (demand paging)

程式 A 的工作集

程式 B 的工作集

Page 29: Windows  記憶體管理

工作集理論模型

t 代表時間點 δ 代表一段時間間隔 w(t, δ) 代表行程的工作集

Page 30: Windows  記憶體管理

頁面替換演算法• 實體記憶體吃緊• 行程使用的頁面總數超過系統中頁面的數量• 需要一個有效率的實體記憶體管理替換頁面的演算法

Page 31: Windows  記憶體管理

頁面替換演算法• 最佳頁面替換演算法 (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)

Page 32: Windows  記憶體管理

最佳頁面替換演算法 (The Optimal Page Replacement Algorithm)

• 分頁錯誤比率最低• 替換未來最不可能被使用到的分頁• 保證在頁框的數目固定之下,會得到最少的分頁錯誤次數• 實際上無法實作,因為對於未來將要使用的分頁不可能完全預測成功• 可提供分頁替換演算法的比較基準

Page 33: Windows  記憶體管理

最佳頁面替換演算法 (The Optimal Page Replacement Algorithm)

Page 34: Windows  記憶體管理

最近未使用頁面替換演算法 (The Not Recently Used Page Algorithm)

– 存取位元 R

– 修改位元 M

– 此 2 位元 (R, M) 有下列 4 種組合,依據順序進行替換• ( 0, 0 ):表示最近沒有被行程使用,也沒有被行程修改,是最佳的替換分頁• ( 0, 1 ):表示最近沒有被行程使用,但是已經被修改過,此分頁須先寫回磁碟後,才可進行替換• ( 1, 0 ):表示最近曾被行程使用,但是沒被修改過,由於可能再次被使用,故盡量不要替換此分頁• ( 1, 1 ):表示最近曾被行程使用,也被修改過,所以需寫回磁碟中,是最差的替換分頁選擇

Page 35: Windows  記憶體管理

先進先出頁面替換演算法 (The First-In First-out Page Replacement Algorithm)

• 每次有新的分頁需置入時,會選擇置入記憶體時間最久的分頁換出• 兩種實作的方法:– 記錄每個分頁被置入到頁框的時間,當每次需要換出分頁時,會找置入時間最早的一頁– 利用 FIFO 佇列來實作,當要進行分頁替換時,就把佇列最前端的分頁換出,再把要置入的分頁放到佇列的末端

• Belady 反常:配置的頁框數目增加,分頁錯誤次數有可能會增加

Page 36: Windows  記憶體管理

先進先出頁面替換演算法 (The First-In First-out Page Replacement Algorithm)

Page 37: Windows  記憶體管理

第二次機會頁面替換演算法 (The Second Chance Page Replacement Algorithm)

– 移位暫存器的大小設定為 0 個位元– 記憶體中每個頁框均對應到一個參考位元,其初始值為 0 ;當某分頁被行程使用時,該參考位元會被設定為 1

– 進行分頁替換時,以先進先出的方式找尋被替換分頁;若找到的頁框參考位元為 0 ,則進行替換;若參考位元為 1 ,則將此分頁的參考位元設定為 0 ,給予此分頁第二次機會,不馬上將它替換;並把此分頁的時間標記設為目前的時間– 繼續用先進先出的方式找尋被替換分頁,直到所有其它的分頁都被替換掉,或是都被給予第二次機會之後,該分頁才會被替換掉– 利用鏈結串列較無效率,可換用環狀佇列方式

Page 38: Windows  記憶體管理

第二次機會頁面替換演算法 (The Second Chance Page Replacement Algorithm)

0

A B C D E F G H

AB C D E F G H

3 7 8 12 14 15 18

3 7 8 12 14 15 18 20

( a )

( b )

最先載入的頁 最常參考的頁

視 A如新載入的分頁參考位元 0

參考位元 1

Page 39: Windows  記憶體管理

第二次機會頁面替換演算法 (The Second Chance Page Replacement Algorithm)(The Clock Page Replacement Algorithm)

C

參考位元 0

參考位元 1

L B

D

E

FG

H

I

A

J

K

Page 40: Windows  記憶體管理

最近最不常使用頁面替換演算法 (The Least Recently Used Page Replacement Algorithm)

• 優先考慮最近不常用的頁面• 以存取頻率來決策替換的頁面• 維護一個頁面串列,每次存取必須要把存取頁面移到串列之首,表示剛剛存取過,維護成本過高,難以硬體實作。

Page 41: Windows  記憶體管理

最不常用頁面替換演算法 (The Not Frequently Used Page Replacement Algorithm)

• 與 LRU 一致,此為軟體實作。• 每個頁面維護一個計數器,初始為 0 ,每次時鐘中斷,系統會將存取位元 (0 or 1) 加到計數器上。• 計數器有增無減,時間越長會影響到頁面替換演算法決策。• 頁面老化演算法改進計數器有增無減的狀況,時鐘中斷修改計數器時,先將計數器右移一位元,把存取位元放入最左邊的位元上。

Page 42: Windows  記憶體管理

Windows 記憶體管理概述• 兩種特權等級 -核心模式 (0) 、使用者模式 (3)

• 核心模式使用系統位置空間 -0x80000000-0xffffffff - 存取自身行程資料也可以存取系統位置空間• 使用者模式使用行程位置空間 -0x00000000-0x7fffffff -只能存取行程自身的資料

Page 43: Windows  記憶體管理

Windows 記憶體管理概述• 應用程式使用記憶體必須先申請根據申請和釋放操作來維護整個虛擬位址空間的記憶體分配情況。• Windows採用 Demand Paging ,當一段虛擬記憶體被使用才為它分配分頁表和實體頁面。• 每個行程虛擬位址空間的分配透過虛擬位址描述項 (Virtual

Address Descriptor) 記錄下來,構成一棵平衡二元樹

Page 44: Windows  記憶體管理

Page Fault處理步驟2. 中斷

可用頁框主記憶體

jump func1move ax,bx

作業系統

func1:

i

分頁表

磁碟4.載入產生分頁錯誤的頁

5. 設定分頁表

1. 參考分頁表 3. 找尋產生分頁錯誤的頁

6.重新執行指令

Page 45: Windows  記憶體管理

Windows 記憶體管理概述• Page Frame Number Database描述實體記憶體每個頁面的狀態。• Page Directory Entry 和 Page Table Entry( 分頁目錄和分頁表 )正確轉譯虛擬位址。 4.3.1

• 位址空間建立後,未獲得實體頁面的虛擬位址時會觸發 page fault 例外來分配頁面、設置分頁表和頁面間的邏輯關係。

• 頁面替換由 working set manager 完成,它執行在一個 balance set manger 的系統緒程中。工作集縮減的過程稱為修剪 (trim)

Page 46: Windows  記憶體管理

Windows 記憶體管理重要元件• 執行體層 - 分配、釋放和管理虛擬位置。• 分頁錯誤例外處理常式 ( 分頁錯誤常式 ) - 分配實體頁面、磁碟資料讀入頁面。• 一組系統緒程 - 平衡集管理員、行程 /堆疊交換器、修改頁面寫出器、零 頁面緒程

Page 47: Windows  記憶體管理

4.2 Windows 記憶體管理995202048 周定緯

Page 48: Windows  記憶體管理

系統位址空間• 在 Intelx86處理器的 Windows 系統中 ,

0x80000000 - 0xf f f f f f f f 是所有行程共用的位址空間 .– i.e. , 2GB - 4GB 是系統位址空間– 在這段位址空間中 , 其配置結構是在核心初始化階段完成的

Page 49: Windows  記憶體管理

系統位址空間初始化• 在核心獲得控制之前 , Windows 載入程式

( ntldr ) 已經打開了 Intel x86 處理器的分頁機制 , 並預先建立了足夠的分頁表以便 16MB 以下的低位址可以透過分頁表來存取其實體記憶體 .

Page 50: Windows  記憶體管理

ntldr

• Windows 載入程式 (NT loader)• 程式碼由兩部分組成–真實模式 ( 16 位元模式 )– 保護模式 ( 32 位元模式 )

Page 51: Windows  記憶體管理

ntldr : 真實模式• 16 位元模式• 執行初始化工作– e.g. , 清除鍵盤緩衝區

• 為切換到保護模式做好基本的環境準備• 將控制權交給 OS loader

Page 52: Windows  記憶體管理

ntldr : 保護模式• 32 位元模式• 預先建構分頁目錄及分頁表來管理實體記憶體• 設置分頁目錄暫存器 , 開啟頁面對應機制• 執行其他的初始化工作– e.g. , I/O 裝置初始化

• 載入核心模組– 預設為 ntoskrnl.exe

• 將核心模組對應到特定的虛擬位址上 , 並將控制權交給其主函式 KiSysemStartup

Page 53: Windows  記憶體管理

WRK 中的元件介面函式字首

Page 54: Windows  記憶體管理

區段暫存器• GDT 的設置是在 ntldr 中完成的– 暫存器 gdtr 的值為 0x 8003f000 – 在 KiSysemStartup 剛獲得控制時 , 其區段暫存器的值如下 :

Page 55: Windows  記憶體管理

區段選擇符格式

Page 56: Windows  記憶體管理

區段描述項格式

Page 57: Windows  記憶體管理

KiSysemStartup

• CS , DS , ES & SS 區段指向了整個位址空間 .– 0x 00000000 – 0x f f f f f 000 • 幾乎是最大位址 , 差最後一個頁面

– “ 區段 + 偏移 ” 形式的邏輯位址直接直接被對應成線性位址• 遮罩了區段機制 , 位址空間平面化

Page 58: Windows  記憶體管理

KiSysemStartup

• KiSysemStartup -> KiInitializekernel– 在啟動處理器 ( P0 ) 上執行全域範圍的核心初始化

• KiInitializekernel -> ExpInitializeExecutive– 對執行體進行初始化

• ExpInitializeExecutive -> MmInitSystem– 初始化執行體子元件

• e.g. , 記憶體管理員– 每個子元件被初始化兩次

• 分別對應於 ” 階段 0 “ 以及 “ 階段 1 “

Page 59: Windows  記憶體管理

核心兩階段初始化• 由於核心元件之間有緊密的耦合關係 , 所以他們的初始化不是簡單地循序執行初始化 .• 階段 0 初始化– 將階段 1 初始化需要用到的資料結構建立起來

• 階段 1 初始化–核心的完全初始化 , 占據了系統初始化相當一部分時間

Page 60: Windows  記憶體管理

與記憶體管理相關的核心初始化過程

Page 61: Windows  記憶體管理

核心初始化過程

Page 62: Windows  記憶體管理

MmInitSystem

• Windows 載入程式 ntldr 只提供了必要的記憶體環境 , 系統空間主要的初始化工作是在 MmInitSystem 函式中完成的• MmInitSystem 包含三部分的程式碼邏輯– 分別對應了 “階段 0” , “階段 1” 以及 “階段

2” 的初始化

Page 63: Windows  記憶體管理

MmInitSystem : 階段 0

• 完成資料結構的初始化以及一些全域變數的設置 , 例如 :– MmHighestUserAddress• 紀錄使用者空間的最高位址 ( 略小於 2GB處 )

– MmUserProbeAddress• 使用者與系統空間的隔離區起始位址 ( size = 64KB )

– MmSystemRangeStart• 系統空間起始位址 ( 2GB處開始 )

Page 64: Windows  記憶體管理

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

Page 65: Windows  記憶體管理

MmInitSystem : 階段 0

• #define MiGetPteAddress(va) – ( ( PMMPTE ) ( ( ( ( ( ULONG ) ( va ) ) >> 12 ) << 2 )

+ PTE_BASE ) )• 給定一個虛擬位址 , 計算出其對應的 PTE 位址 .– i.e. , 虛擬位址所在頁面的 PTE 位址

• PTE_BASE = 0x c 0000000

Page 66: Windows  記憶體管理

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 ( 實體位址擴充 )

Page 67: Windows  記憶體管理

Note

• ntldr 在將控制權交給核心之前 , 已將核心 , HAL 和一些啟動的驅動程式對應到 0x800000000 偏上的位置處 .– 在前述記憶體區域劃分好之後 , 這些程式稍後將被重定到高位記憶體 ( 系統 PTE ) 區域 .

Page 68: Windows  記憶體管理

MmInitSystem : 階段 0

• 設定系統檢視 ( system view ) 大小為 16MB• 設定工作空間 ( session ) 大小為 48MB– 0xbd000000 - 0xb f f f f f f f– 0xc0000000 之上的 48MB

Page 69: Windows  記憶體管理

工作階段空間和系統檢視的記憶體配置結構

Page 70: Windows  記憶體管理

MmInitSystem : 階段 0

• 初始化系統快取的位置– MmSystemCacheStart = 0x c 1000000– #define MM_SYSTEM_CACHE_END 0x e 1000000

• 分頁集區的變數設置– MmPagedPoolStart = 0x e1000000– MmSizeOfPagedPoolInBytes

• 預設 32 MB , 未來會再進行調整• 計算系統 PTE 數量– 設定系統全域變數 MmNumberOfSystemPtes

• 介於 7000 – 50000 之間

Page 71: Windows  記憶體管理

MmInitSystem : 階段 0

• 初始化與堆積記憶體管理有關的全域變數 .• MmInitSystem -> MiInitMachineDependent– 此時才真正讓 Windows 的虛擬記憶體運轉起來– MmInitSystem • 劃分虛擬位址空間

– MiInitMachineDependent • 真正建立分頁目錄項目以及分頁表來對應核心各個區域

Page 72: Windows  記憶體管理

MmInitSystem : 階段 0

• 初始化與實體記憶體相關的全域變數– MmInitSystem -> MmInitializeMemoryLimits– 獲得有關實體記憶體基本資訊

• 將 ntldr 載入的啟動驅動程式重定到 PTE 區域– MmInitSystem -> MiReloadBootLoadedDrivers– 使得這些程式也能得到 分頁機制的保護

Page 73: Windows  記憶體管理

MmInitSystem : 階段 0• 設置下列全域變數

– MmMaximumDeadKernelStacks– MmModifiedPageMaximum– MmSystemCacheWsMinimum– MmDataClusterSize– MmCodeClusterSize– MmReadClusterSize– MmInPageSupportMinimum– MmFreedExpansionPoolMaximum

• 這些變數用於控制系統空間中一些特殊用途的實體記憶體頁面的數量 , 或者上下限 .

Page 74: Windows  記憶體管理

MmInitSystem : 階段 0

• 調整可用實體記憶體頁面的數量–調整全域變數 MmResidentAvailable–從目前可用頁面數量減掉• 32 個保留頁面• 非分頁擴充所需要的頁面數• 系統快取所佔用的最少實體頁面數

Page 75: Windows  記憶體管理

MmInitSystem : 階段 0

• 建立系統快取結構– 系統快取結構位址 • MmSystemCacheWorkingSetList = 0x c0c00000

– 系統快取位址• MmSystemCacheStart = 0x c1000000

– 系統快取最大可能位址 = 0x e1000000• 取決於 MaximumSystemCacheSize 的變化情況

– MmInitSystem -> MiInitializeSystemCache• 初始化快取系統工作集 , 並建立相關管理資料結構

Page 76: Windows  記憶體管理

MmInitSystem : 階段 0

• 設置全域變數 MmTotalCommitLimit– 代表最多可提交的記憶體數量 , 及最多可以兌現多少實體記憶體– MmTotalCommitLimitMaximum =

MmTotalCommitLimit• MmMaximumWorkingSetSize– = “ 總可用頁面數” - 512

Page 77: Windows  記憶體管理

MmInitSystem : 階段 0

• MmInitSystem -> MiBuildPagedPool–建立分頁集區

• MmInitSystem-> MiInitializeLoadedModuleList– 初始化已載入的模組表 , 將這些模組對應到系統空間中

Page 78: Windows  記憶體管理

• 階段 0 初始化

翁志嘉

Page 79: Windows  記憶體管理

MiInitMachineDependent ( ) //建立當前 process 的頁目錄

PointerPte = MiGetPdeAddress (PDE_BASE); // 得到 process 對應的 PDE 位址

PdePageNumber = MI_GET_PAGE_FRAME_FROM_PTE(PointerPte); // 得到 PoiterPte 所指到的 PDE 有多少個 pageCurrentProcess = 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

Page 80: Windows  記憶體管理

• #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

i386.h 程式碼片段

Page 81: Windows  記憶體管理

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)

Page 82: Windows  記憶體管理

MI_GET_PAGE_FRAME_FROM_PTE (mi386.h 2542 行 )

#define MI_GET_PAGE_FRAME_FROM_PTE(PTE) ((PTE)->u.Hard.PageFrameNumber)

Page 83: Windows  記憶體管理

//// Unmap the low 2Gb of memory.//

PointerPde = MiGetPdeAddress (0);LastPte = MiGetPdeAddress (KSEG0_BASE);MiZeroMemoryPte (PointerPde, LastPte - PointerPde); //將分頁目錄表 (PDE) 中對應 0~2GB ( 使用者記憶體空間 ) // 之間分頁目錄寫成 0 ,意味目前 Process 不使用這部分空間。

Page 84: Windows  記憶體管理

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;

Page 85: Windows  記憶體管理

透過 MemoryDescriptorListHead 可以得到全域變數 MmNumberOfPhysicalPages ( 實體記憶體 page 的數量 )以及 MmHighestPossiblePhysicalPage( 空閒記憶體的最低位址 )

接著設置 MmDynamicPfn( 最高可用的實體位址頁編號 ) 以及 MmHighestPossiblePhysicalPage( 最高可能的實體頁面 )

然後調整 MmSizeOfNonPagedPoolInBytes (非分頁集區的大小 )以及 MmMaximumNonPagedPoolInBytes(非分頁集區的最大尺寸 )

Page 86: Windows  記憶體管理

接下來的就是計算 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

Page 87: Windows  記憶體管理

PointerPte = MiGetVirtualAddressMappedByPte (StartPde);//反推,得到 StartPde 的 Page Table 所在的虛擬記憶體

//#define MiGetVirtualAddressMappedByPte(PTE) ((PVOID)((ULONG)(PTE) << 10))

RtlZeroMemory (PointerPte, PAGE_SIZE); //初始化此 page table ,全部填 0StartPde += 1;

}

Page 88: Windows  記憶體管理

Windows 的分頁目錄自對應方案虛擬記憶體共有 32 位元

每個頁目錄索引以及分頁目錄索引均為 4bytes ,因此需要 4k的頁目錄和 4M 的頁表, windows將頁表安排在 0xc0000000~0xc0400000, 頁目錄安排在 0xc0300000~0xc0400000 。

Windows 的分頁目錄自對應指的是頁目錄項本身也會用作頁表項, 其優點是讓 PDE 及 PTE 能夠根據他們自己的虛擬位址推匯出所指向的實體頁面的虛擬位址

頁目錄索引(10bit)

分頁表索引(10bit)

偏位移量 (12bit)

Page 89: Windows  記憶體管理

Windows 的分頁目錄自對應方案 ( 續 )

若 PDE 位址為 0xc030000011000000 00110000 00000000 00000000將 PDE左移 10 位得到 0xc000000011000000 00000000 00000000 00000000

若 PDE 位址為 0xc0300c0011000000 00110000 00001100 00000000將 PDE左移 10 位得到 0xc030000011000000 00110000 00000000 00000000

在此,我們可以清楚看出,當 PDE=0xc0300c00 時,所有的分頁表會位於 0xc0300000~0xc0400000 之間,也因如此,構成了分頁目錄自對應方案的優點。

Page 90: Windows  記憶體管理

PFN 資料庫與非分頁集區管理• Windows 在系統位址空間高位處保留了一塊位址範圍用做系統當機時的資訊轉存區域,並為其分配了一個頁表,其起始位址為 0xffbe0000 ,大小不超過 4 MB 。 • MiInitializeNonPagedPool( ) //建立非換頁記憶體池的管理結構• MiInitializeNonPagedPoolThresholds( ) //設定非換頁記憶體池的高、低閾值 • 然後分配 PFN 所需的實體頁,範圍從 FirstPfnDatabasePage開始,總共

MxPfnAllocation 個頁面。• 根據系統載入程式傳遞過來的實體記憶體描述項串列,檢查所有的記憶體描述項,並把可用的記憶體都加入到 PFN 資料庫的空閒串列。

Page 91: Windows  記憶體管理

PFN 資料庫與非分頁集區管理 ( 續 )

• 接下來掃描 PFN 資料庫所用到的 PTE ,並把它們對應的頁面標記為已經在使用 。 • 呼叫 InitializePool ( )初始化非分頁集區。至此,非分頁集區以建立起來並可以使用。• 透過 MiInitializeSystemPtes( ) 對系統的 PTE 進行初始化。• 接著初始化目前 process 的記憶體管理結構,並建立起工作集串列,包含建立一個 PDE ,以及初始化該 PDE 所指的 page table 。• 最後,將管理記憶體所需的實體頁面標記為已在使用,至此, MiInitMachineDependent 函式完成其初始化工作。

Page 92: Windows  記憶體管理

• 階段 1 初始化• 階段 2 初始化• 系統位址空間記憶體管理– 系統非分頁集區的管理演算法

995202031 秦承鴻

Page 93: Windows  記憶體管理

核心、 HAL等系統模組的映象區PFN 資料庫非分頁集區

系統快取額外區系統 PTE額外區

系統檢視工作階段空間

分頁表超空間和行程工作集

系統快取結構系統快取分頁集區

系統 PTE 區域非分頁集區擴充區

當機轉存區保留區

0x80000000

MmPfnDatabase

MmNonPagedPoolStart

MiSystemCacheStartExtra

MiSystemViewStart

MmSeesionBase

0xc0000000

0xc0400000

MmSystemCacheWorkingSetListMmSystemCacheStart

MmPagedPoolStart

MmNonPagedSystemStart

MmNonPagedExpansionStart

0xffbe0000

0xffffffff

部分

分頁表是否已分配 | 頁面是否已分配

MiMaximumSystemCacheSizeExtra( 個頁面 )

Page 94: Windows  記憶體管理

全域變數名 典型取值 全域變數名 典型取值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

Page 95: Windows  記憶體管理

階段 1 初始化階段 1 :MmInitSystem

MiInitMachineDependent

MiMapBBTMemory

MiSectionInitialization

申請 PTE物件

如果處理器支援大頁面,並且在前面初始化過程中有紀錄下來要轉換成大頁面的記憶體區域,則把這些區域轉換成大頁面對應。為 BBT 預留一塊記憶體緩衝區。由於在預設配置下, BBTPagesToReserve 為 0 ,所以此函式什麼都不做。將 MmSharedUserDataPte指向此 PTE物件,該 PTE紀錄使用者共用資料頁的 PTE ,位於 0xffdf0000。接下來把該 PTE指定到行程位址空間的0x7ffe0000 所對應的 PTE 中。

1

2

3

4

建立記憶體區段物件型別,建立區段提領系統執行緒,並且建立記憶體區段物件,再插入到目前行程控制碼表中。

Page 96: Windows  記憶體管理

階段 1 初始化階段 1 :MmInitSystem

5 MiSessionWideInitializeAddressMiInitializeSessionWsSupportMiInitializeSessionIds

初始化階段空間。

建立修改頁面寫出器 (modified page writer) 的系統執行緒。6

MiInitializeMemoryEvents

初始化系統記憶體事件,包括高記憶體和低記憶體事件,以及分頁集區和非分頁集區的高低事件。

7

啟動平衡集管理員8

兩個系統緒程,分別為KeBalanceSetManger 和KeSwapProcessOrStack函式。

MiStartZeroPageWorkers

啟動零化頁面的系統輔助執行緒。9

MiWriteProtectSystemImage10

對所有已經載入的模組設置其保護屬性。

至此,階段 1 初始化完成,全域變數 MiFullyInitialized 設置為 1。

Page 97: Windows  記憶體管理

階段 2 初始化• MmInitSystem只有呼叫MiEnablePagingTheExecutive函式,將目前已載入的模組中的可分頁程式碼區變成可分頁的,它找到每個模組的 PAGE 記憶體區,然後呼叫

MiEnablePagingOfDriverAtInit函式以改變相關 PTE 中的標記。– 讓可分頁程式碼區的 PTE 可以在記憶體吃緊的情況下騰出實體記憶體頁面

• 記憶體管理員的初始化工作全部完成,而且系統空間已經完全建立起來。

Page 98: Windows  記憶體管理

總結階段 0 初始化 1.劃分系統位址空間,它充分可慮到實體記憶體

的數量和啟動選項指定的要求,使得最終得到的各部分區域的範圍相對比較合理。2.負責建立起分頁目錄和分頁表結構,並且完成非分頁區域的實體頁面分配。

階段 1 初始化 記憶體管理工作的初始化,包括建立修改寫出器和平衡集管理員,以及零化頁面工作。

階段 2 初始化 只是簡單地使系統模組中的分頁程式碼區可被分頁而已。

Page 99: Windows  記憶體管理

系統位址空間記憶體管理• 在系統位址空間中,有些部分是供一些特殊模組使用的,比如工作階段空間是由工作階段管理員和 Windows子系統使用的;而分頁集區和非分頁集區則是提供給系統核心模組和裝置驅動程式使用的。• 在分頁集區中分配的記憶體有可能在實體記憶體吃緊的情況下被換出到外部記憶體;而非分頁集區中分配的記憶體總是處於實體記憶體中。

Page 100: Windows  記憶體管理

系統位址空間記憶體管理執行體記憶體集區

(非分頁 )執行體記憶體集區

( 分頁 )

系統非分頁集區 非分頁集區擴充區域 系統分頁集區 系統 PTE 區域

Windows核心中的動態記憶體管理結構

Page 101: Windows  記憶體管理

系統非分頁集區的管理演算法• 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;

Page 102: Windows  記憶體管理

系統非分頁集區的管理演算法• 非分頁集區有兩部分:– 基本記憶體集區:其中所有頁面都已經分配了實體頁面– 擴充記憶體集區:只有當基本區無法滿足記憶體申請需求時才會分配真正的實體頁面

• 由於非分頁集區的空閒頁面已經被對應到實體頁面,所以 Windows充分利用這些頁面自身的記憶體來建構起一組空閒頁面串列。

Page 103: Windows  記憶體管理

Owner

Owner

3 2 1 0空閒串列陣列: MmNonPagedPoolFreeListHead

List Size Sign Owner List Size Sign Owner

單頁面空閒串列

List Size Sign Owner Owner List Size Sign Owner

List Size Sign Owner Owner

List Size Sign Owner

雙頁面空閒串列

3 頁面空閒串列

OwnerList Size Sign Owner Owner

List Size Sign Owner

>=4 頁面空閒串列

Page 104: Windows  記憶體管理

系統非分頁集區的管理演算法• 對於已經確定的 SizeInPages 個頁面, MiAllocatePoolPages函式分別找到其起始頁面和結束頁面在 PFN 資料庫中的紀錄,並且分別設置它們的 StartOfAllocation 和 EndOfAllocation 位元。• 如果在空閒串列陣列中搜尋不到滿足條件的空閒節點,則 MiAllocatePoolPages函式試圖擴充非分頁集區,並滿足所要求的頁面數。

Page 105: Windows  記憶體管理

系統非分頁集區的管理演算法• MiFreePoolPages

– 對於一個給定的起始位址 StartingAddress ,找到它的 PTE ,並提取出 PFN ,從而找到 PFN 資料庫中起始頁面的 PFN項目– 凡是透過 MiAllocatePoolPages 分配得到的連續頁面,其首頁面的 PFN項目的 StartOfAllocation 位元必定是 1 ,沿著此 PFN項目進行搜尋,可以找到結束頁面,其 PFN項目的

EndOfAllocation 位元為 1

• 為了維護非分頁集區中的空閒串列結構,被回收的頁面如果有可能的話,還要跟它們後續的空閒頁面或者它們前面的空閒頁面合併成一個更大的空閒區塊。

Page 106: Windows  記憶體管理

系統非分頁集區的管理演算法• 如果 StartingAddress指示了一個非分頁擴充集區中的位址,則可能有必要呼叫

MiFreeNonPagedPool函式來回收他的頁面。

Page 107: Windows  記憶體管理

系統非分頁集區的管理演算法• 在收回單個頁面的時候,如果MiFreePoolPages 函式發現, MiNonPagedPoolSListHead 串列中的頁面數小於 MiNonPagedPoolSListMaximum ,則將此頁面加入到 MiNonPagedPoolSListHead 串列中。• 因此,在 MiAllocatePoolPages 的開始處,如果使用者要申請單個頁面,並且

MiNonPagedPoolSListHead 串列不為空的話,則直接從串列開頭提取一個頁面回傳給使用者。

Page 108: Windows  記憶體管理

Windows 核心原理實務開發系統分頁集區的管理演算法995402004謝正達

Page 109: Windows  記憶體管理

• 不合適使用非分頁集區的空閒頁面串列作法– 分頁集區中的空閒頁面不保證有對應的實體頁面– 出於管理的原因而為分頁集區的空閒頁面分配實體頁面,不符合分頁集區的設計目的

Page 110: Windows  記憶體管理

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;

Page 111: Windows  記憶體管理

MM_PAGED_POOL_INFO

MM_PAGED_POOL_INFO

PagedPoolAllocationMap

EndOfPagedPoolBitmap

NextPdeForPagedPoolExpansion

FirstPteForPagedPoolLastPteForPagedPool

PagedPoolHintPagedPoolCommit

AllocatedPagedPool

Page 112: Windows  記憶體管理

• 全域分頁集區– MmPagedPoolInfo

• 工作階段空間– MmSessionSpace.PagedPoolInfo

Page 113: Windows  記憶體管理

• 分頁集區啟始位址– 系統全域範圍• MnPagedPoolStart(變數 )

– 工作階段空間• MiSessionPoolStart(變數 )

Page 114: Windows  記憶體管理

• 透過點陣圖 (bitmap) 管理分頁集區– 一個頁面的分配與否,由該頁面所對應的位元來表達– PagedPoolAllocationMap

• 用以指明每一個頁面的分配狀態– EndOfPagedPoolBitmap

• 標明每個頁面是否為一次記憶體申請的最後一個頁面– FirstPteForPagedPool– LastPteForPagedPool

• 規定記憶體集區的位址範圍– NextPdeForPagedPoolExpansion

• 定義分頁集區下次的擴充位置– PagedPoolCommit

• 記錄有多少個頁面已經分到了記憶體– AllocatedPagedPool

• 記錄分頁集區分配到了多少頁面– PagedPoolHint

• 分配頁面時的起始搜尋位置

Page 115: Windows  記憶體管理

環境變數• MnInitSystem–呼叫MiBuildPagedPool建立系統的分頁集區大小– MiBuildPagedPool 用於初始化MnPagedPoolInfo的所有成員– MnSizeOfPagedPoolInBytes– MnSizeOfPagedPoolInPages• 記錄分頁集區的大小• 最大不超過 MnNonPagedSystemStart-

MnPagedPoolStart

Page 116: Windows  記憶體管理

• MmPagedPoolStart• MmPagedPoolEnd– 分別紀錄分頁集區的起始位址與結束位址– MmPagedPoolInfo 中的 FirstPteForPagedPool 與

LastPteForPagedPool 可根據這兩變數的值直接匯出

Page 117: Windows  記憶體管理

初始化• 呼叫MiBuildPagedPool 分配好一個分頁表,即起始位置的 PDE• NextPdeForPagedPoolExpansion即為接下來的分頁表位址• 呼叫MiCreateBitMap函式建立 BitMap–非分頁集區分配– PagedPoolAllocationMap(1024 bits) 設為 0– EndOfPagedPoolBitmap相同初始化為 0

Page 118: Windows  記憶體管理

• MiBuildPagedPool呼叫 InitializePool 初始化執行體分頁集區• 設置預警閥值– MiLowPagedPoolThreshold– MiHighPagedPoolThreshold

• 如果系統禁止執行體記憶體集區分頁,即全域變數 MmDisablePagingExecutive 中的MM_PAGED_POOL_LOCKED_DOWN旗標將被設定– 分頁集區被設定成非分頁集區

Page 119: Windows  記憶體管理

分頁配置與釋放• MiAllocatePoolPages– PoolType決定在那個記憶體集區中申請頁面

• MiFreePoolPages

Page 120: Windows  記憶體管理

• 分配過程–根據 PoolType 找到對應的記憶體集區

MM_PAGED_POOL_INFO 結構 –呼叫 RtlFindClearBitsAndSet 找尋

PagedPoolAllocationMap 中連結零位元,如果無法找到,則設法擴充分頁集區(NextPdeForPagedPoolExpansion 後移 ) 再重新呼叫 RtlFindClearBitsAndSet

Page 121: Windows  記憶體管理

• MiAllocatePoolPages函式,更新PagedPoolInfo 中已分配頁面的數量– AllocatedPagedPool欄位–如果數量小於 MiLowPagedPoolThreshold 則發出預警訊號 (MiLowPagedPoolEvent)–檢查這些頁面是否需要刷新他們的 TLB• 是呼叫 KeFlushSingleTB, KeFlushMultipleTB,

KeFlushEntireTB函式刷新 TLB

Page 122: Windows  記憶體管理

• 呼叫MiFreePoolPages 回收頁面–傳入的 StartingAddress介於 MmPagedPoolStart和 MmPagedPoolEnd 之間,說明這是系統分頁集區的頁面– 利用 PagedPoolInfo 中的兩個 BitMap驗證位址的有效性,並修改 BitMap 與更新

AllocatedPagedPool 和 PagedPoolCommit欄位

Page 123: Windows  記憶體管理

• MiFreePoolPages幾項說明– 如果被分配為非分頁集區,則只需要維護 BitMap 與相關的全域變數與記憶體區變數– 如果是單個頁面被釋放,則有可能加入到一個單串列中。單串列由 MiPagedPoolSListHead 記錄,本串列最多記錄 8 個單頁面,如果下次需要申請單頁面,則

MiAllocatedPoolPages ,直接從該串列提取– 遵從系統分頁集區的管理

• MiChargeCommitmentCanExpand函數• MiReturnCommitment函式• MiDeleteSystemPageableVm函式