標籤:des style blog http color os 使用 io for
實體記憶體是相對比較緊張的資源,合理利用將是一個作業系統的效能的關鍵。Windows 2000/XP內部使用一個稱為頁框資料庫(Page Frame Database)的結構用於描述實體記憶體的狀態。本文將從這一結構入手詳述Windows實體記憶體的組織與管理。
Windows將實體記憶體按PAGE_SIZE(在x86上,為0x1000位元組,即4K)為單位,將其劃分,每一單元在頁框資料庫中均有一項描述其狀態及用途等。頁框資料庫實際上是由這些描述每一頁情況結構的數組。頁框資料庫由核心變數MmPfnDatabase指定,而資料庫中的項數則由MmNumberOfPhysicalPages指定,項數索引叫Page Frame Number(PFN)來表示。MmNumberOfPhysicalPages通常略低於系統實際擁有的實體記憶體頁數,系統在初始化階段保留部分頁面讓作業系統本身使用。需要指出的是頁框資料庫只描述狹義上的實體記憶體,不包含其他映射的物理裝置的記憶體。
Windbg的!pfn命令用於對任一頁記憶體的狀態及用途等進行分析,如下所示:
kd> dd MmPfnDatabase l 1
80547438 80c00000
kd> !pfn 143
PFN 00000143 at address 80C01E48
flink 00000500 blink / share count 00000001 pteaddress E1085174
reference count 0001 Cached color 0
restore pte 00B5AC24 containing page 0096D8 Active P
Shared
《Inside Windows 2000》中將PFN的各個欄位解釋的已經非常清楚了。這裡我只是簡要進行說明:
flink與blink用於將特定狀態的頁面連成一個鏈表,系統中核心變數MmZeroedPageListHead、MmFreePageListHead、MmStandbyPageListHead、MmModifiedPageListHead、MmModifiedNoWritePageListHead、MmBadPageListHead用於指示這些狀態的頁面的鏈表頭。從這些變數名很容易明白各鏈表的頁面狀態,在Windows中頁框資料庫中共有8個狀態,另兩個為:Active與Transition狀態。這8個狀態由pfn的type(offset:0xd,size:byte)欄位中的前3bit指示。
pteaddress是指向這一頁面的pte地址。經過分析,主要有如下三種情況:
a. pteaddress為0或0xffffffff,根據pfn指示的狀態,可識別是ZeroedPage或是FreePage。
b. pteaddress為0xC*******,表明這一頁面當前有系統或某一進程獨佔,並且在進程或系統工作集中。
c. pteaddress為0xE*******,說明這是一個prototype pte,也就是說這個頁面是共用的。詳細請參閱我的《探究Windows 2000/XP原型PTE》。
restore pte,在《Inside Windows 2000》中稱為original pte。其作用是指示這一頁面的back-store位置,即資料在磁碟中某一pagefile或是mapped file中的位置。譬如在上面提及的情況c中,其一般是指向mapped file的某一subsection,所以在內部其稱為Subsection PTE,由MMPTE_SUBSECTION結構定義。而另外一種情況其可能是一個指向pagefile的pte,由MMPTE_SOFTWARE結構定義。這一點,上次我提及時存在錯誤。MMPTE_SUBSECTION的具體bit定義如下:
Valid : Pos 0, 1 Bit
SubsectionAddressLow : Pos 1, 4 Bits
Protection : Pos 5, 5 Bits
Prototype : Pos 10, 1 Bit
SubsectionAddressHigh : Pos 11, 20 Bits
WhichPool : Pos 31, 1 Bit
最高位WhichPool是指示這個Subsection位於哪個pool中(NonPagedPool或是PagedPool中),Valid為0,指示這不是一個x86硬體可以識別的pte,由MiDispatchFault分析。由Subsection pte轉換成Subsection地址的演算法我在底下提供的代碼中給出了。
這一描述基本闡述了Subsection PTE的作用,用於定位由PFN所指定的頁面位於相應的Mapped File的位置。為了更好的解釋好這一過程,《Inside Windows 2000》中使用了一個框圖來解釋記憶體管理器內部的這幾個千絲萬縷的聯絡,但各個資料結構,如PFN,SEGMENT等等介紹的不夠詳盡,並且之間的轉換演算法均沒有提及。是我根據Windows XP Professional Build 2600的情況,重新製作的一幅圖.
Windbg提供了一個!memusage命令通過分析subsectin pte得到系統中各個mapped file的使用記憶體情況,底下的代碼,只是詳細的列出了某些頁面由哪些mapped file使用,並沒有像!memusage有詳細的統計功能,不過通過這一代碼與我先前提供的文章,也能基本上明白上面這幅圖之間複雜關係。
1 /* 2 For test purpose,I define the below constant,but no say 3 MmSubsectionBase and MmNonPagedPoolEnd are fixed in 4 Windows 2000 and Windows XP. They are initialized on system 5 boot phase by ntoskrnl and rely on the system physical memory size etc. 6 */ 7 #define WIN2000_2195 8 #ifdef WINXP_2600 9 #define MmSubsectionBase 0x80d2100010 #define MmNonPagedPoolEnd 0xffbe000011 #endif12 #ifdef WIN2000_219513 #define MmSubsectionBase 0x014 #define MmNonPagedPoolEnd 0xffb7f00015 #endif16 17 #define MmPfnDatabase 0xffb7f000 //Please redefine it on your machine.18 #define MmNumberOfPhysicalPages 0x3f7d //Please redefine it on your machine.19 20 /*21 Portion of nt!MiGetSubsectionAndProtoFromPte22 Get Subsection from restore pte(original pte) at PFN Database Entry23 disasm by WebCrazy([email protected]) athttp://webcrazy.yeah.net24 Thanks to wuzq([email protected]) for light!25 */26 27 unsigned int MiGetSubsectionAndProtoFromPte(int pte)28 {29 unsigned int subaddr;30 if(pte < 0){ 31 subaddr = MmSubsectionBase+(((pte & 0x1e) <<2) | ((pte>>4) & 0x7ffff80)) ;32 }else{33 subaddr = MmNonPagedPoolEnd-(((pte & 0x1e) <<2) | ((pte>>4) & 0xfffff80)) ;34 }35 return subaddr;36 }37 38 /* 39 I release memusage() to dump Control Area.40 Only mapped file control area were dump.41 Please see windbg !memusage command.42 */43 44 45 void memusage()46 {47 unsigned int *pfndatabase = MmPfnDatabase;48 unsigned int numberphys = MmNumberOfPhysicalPages;49 50 unsigned int restorepte,pfn=0,ppte,subsection;51 52 unsigned char flag=0;53 static unsigned int flagnum[8];54 static char *flagdesc[8]=55 {"Zeroed","Free","Standby","Modified","ModNoWrt","Bad","Active","Trans"};56 memset(flagnum,0,sizeof(flagnum));57 58 for(;pfn<numberphys;pfn++){59 flag = *(char *)((char *)pfndatabase+0xd);60 flag &= 0x07;61 flagnum[flag]++;62 pfndatabase+=0x18/0x04;63 }64 65 DbgPrint("\nMemUsage:\n");66 for(flag=0;flag<8;flag++)67 DbgPrint("%10s:%04d(%08dK)\n",flagdesc[flag],flagnum[flag],flagnum[flag]*4);68 69 70 pfndatabase = MmPfnDatabase;71 for(pfn=0;pfn<numberphys;pfn++){72 ppte=*((unsigned int *)(pfndatabase+0x1));73 restorepte=*((unsigned int *)(pfndatabase+0x4));74 flag = *(char *)((char *)pfndatabase+0xd);75 flag &= 0x07;76 77 if(ppte>=0xE1000000&&ppte<0xF0000000){78 subsection=MiGetSubsectionAndProtoFromPte(restorepte);79 DbgPrint("pfn:%04X,ppte:%08X,restorepte:%08X,subsection:%08X,ca:%08X,80 flag:%10s\n",pfn,ppte,restorepte,subsection,81 MmIsAddressValid((void *)subsection)?*(unsigned int *)subsection:82 0x11111111,flagdesc[flag]);83 }84 pfndatabase+=0x18/0x04;85 }86 }
[轉]解析Winndows 2000/XP實體記憶體管理