Windows記憶體管理學習筆記(二)—— 實體記憶體的管理
-
- 實體記憶體
-
- 實驗一:了解MmNumberOfPhysicalPages
- MmPfnDatabase
-
- _MMPFN
-
- 實體頁狀态
- 六個連結清單
- 實驗二:了解零化連結清單
- 實驗三:檢視程序占用的所有實體頁
實體記憶體
最大實體記憶體
- 10-10-12分頁:最多識别4GB實體記憶體
- 2-9-9-12分頁:最多識别64GB實體記憶體
作業系統限制
- 在xp系統中,即使采用2-9-9-12分頁,仍然無法使用超過4GB的實體記憶體(可了解為 4GB以上的記憶體條)
- 而在windows 2003或windows 2008系統中,即使為32位系統,但若采用2-9-9-12分頁,就可以識别4GB以上的實體記憶體
思考:為什麼?
答案:由核心檔案中的幾個函數限制
實際實體記憶體
實體記憶體總數 = MmNumberOfPhysicalPages * 4
實驗一:了解MmNumberOfPhysicalPages
1)打開任務管理器,檢視實體記憶體
2)檢視MmNumberOfPhysicalPages(機關:實體頁)
指令:dd MmNumberOfPhysicalPages
3)計算實體記憶體
結論:
實體記憶體總數 = MmNumberOfPhysicalPages * 4
思考:這麼多實體記憶體,作業系統如何進行管理
答案:通過全局數組
MmPfnDatabase
MmPfnDatabase
描述:
- 全局結構體數組,稱為“頁幀資料庫”,包含了目前作業系統中所有的實體頁
- 每一個實體頁都有一個對應的MMPFN結構體
- 通過全局變量MmPfnDatabase可以找到這個結構體的起始位置(在WinDbg中使用指令
進行檢視)dd MmPfnDatabase
- 每一個MMPFN結構體之間在記憶體中是緊挨着的
定義:
_MMPFN *MmPfnDatabase
長度:
MmNumberOfPhysicalPages
_MMPFN
//FROM WinDbg
nt!_MMPFN
+0x000 u1 : __unnamed
+0x004 PteAddress : Ptr32 _MMPTE
+0x008 u2 : __unnamed
+0x00c u3 : __unnamed
+0x010 OriginalPte : _MMPTE
+0x018 u4 : __unnamed
//FROM WRK v1.2
typedef struct _MMPFN {
union {
PFN_NUMBER Flink;
WSLE_NUMBER WsIndex;
PKEVENT Event;
NTSTATUS ReadStatus;
//
// Note: NextStackPfn is actually used as SLIST_ENTRY, however
// because of its alignment characteristics, using that type would
// unnecessarily add padding to this structure.
//
SINGLE_LIST_ENTRY NextStackPfn;
} u1;
PMMPTE PteAddress;
union {
PFN_NUMBER Blink;
//
// ShareCount transitions are protected by the PFN lock.
//
ULONG_PTR ShareCount;
} u2;
union {
//
// ReferenceCount transitions are generally done with InterlockedXxxPfn
// sequences, and only the 0->1 and 1->0 transitions are protected
// by the PFN lock. Note that a *VERY* intricate synchronization
// scheme is being used to maximize scalability.
//
struct {
USHORT ReferenceCount;
MMPFNENTRY e1;
};
struct {
USHORT ReferenceCount;
USHORT ShortFlags;
} e2;
} u3;
#if defined (_WIN64)
ULONG UsedPageTableEntries;
#endif
union {
MMPTE OriginalPte;
LONG AweReferenceCount;
};
union {
ULONG_PTR EntireFrame;
struct {
#if defined (_WIN64)
ULONG_PTR PteFrame: 57;
#else
ULONG_PTR PteFrame: 25;
#endif
ULONG_PTR InPageError : 1;
ULONG_PTR VerifierAllocation : 1;
ULONG_PTR AweAllocation : 1;
ULONG_PTR Priority : MI_PFN_PRIORITY_BITS;
ULONG_PTR MustBeCached : 1;
};
} u4;
} MMPFN, *PMMPFN;
MMPFN與實體頁的對應關系:
- 通過目前MMPFN結構體找到對應的實體頁
實體頁 = 目前_MMPFN索引值*0x1000
- 通過目前實體頁找到對應的MMPFN結構體
_MMPFN = *MmPfnDatabase + 0x1c*(實體頁/0x1000)
實體頁狀态
MMFPN->u3.e1定義:
//FROM WRK v1.2
typedef struct _MMPFNENTRY {
USHORT Modified : 1;
USHORT ReadInProgress : 1;
USHORT WriteInProgress : 1;
USHORT PrototypePte: 1;
USHORT PageColor : 4;
USHORT PageLocation : 3; //決定了目前頁的狀态,空閑情況下分為六種狀态
//0:MmZeroedPageListHead
//1:MmFreePageListHead
//2:MmStandbyPageListHead
//3:MmModifiedPageListHead
//4:MmModifiedNoWritePageListHead
//5:MmBadPageListHead
USHORT RemovalRequested : 1;
USHORT CacheAttribute : 2;
USHORT Rom : 1;
USHORT ParityError : 1;
} MMPFNENTRY;
六個連結清單
描述:windows通過六個連結清單,将所有相同類型的實體頁串到一起
-
零化連結清單(是系統在空閑的時候進行零化的,不是程式自己清零的那種)MmZeroedPageListHead
-
空閑連結清單(實體頁是周轉使用的,剛被釋放的實體頁是沒有清0,系統空閑的時候有專門的線程從這個隊列摘取實體頁,加以清0後再挂入MmZeroedPageListHead)MmFreePageListHead
此時,MMPFN對應結構體如下:MMPFNLIST MmZeroedPageListHead = { 0, // Total ZeroedPageList, // ListName MM_EMPTY_LIST, //Flink MM_EMPTY_LIST // Blink };
typedef struct _MMPFN { PFN_NUMBER Flink; PMMPTE PteAddress; PFN_NUMBER Blink; u3; MMPTE OriginalPte; u4; } MMPFN, *PMMPFN;
-
備用連結清單(當系統記憶體不夠的時候,作業系統會把實體記憶體中的資料交換到硬碟上,此時頁面不是直接挂到空閑連結清單上去,而是挂到備用連結清單上,雖然我釋放了,但裡邊的内容還是有意義的)MmStandbyPageListHead
- MmModifiedPageListHead
- MmModifiedNoWritePageListHead
-
壞鍊MmBadPageListHead
實驗二:了解零化連結清單
1)在WinDbg中檢視全局變量MmPfnDatabase的值
2)檢視全局變量MmZeroedPageListHead的值
3)定位第一個零化連結清單
公式:
MmZeroedPageList[0] = MmPfnDatabase + MmZeroedPageListHead[3]*0x1c
4)檢視後四項(紅色代表Flink,藍色代表Blink)
總結:零化連結清單結構如下圖所示
實驗三:檢視程序占用的所有實體頁
1)在WinDbg中定位目标程序
2)檢視該程序的EPROCESS結構體,定位偏移為0x1f8的成員
指令:kd> dt _EPROCESS 866bf7e8
kd> dt _EPROCESS 866bf7e8
ntdll!_EPROCESS
......
+0x1f8 Vm : _MMSUPPORT
......
3)檢視_MMSUPPORT結構體
指令:dt _MMSUPPORT 866bf7e8+0x1f8
ntdll!_MMSUPPORT
+0x000 LastTrimTime : _LARGE_INTEGER 0x01d6e998`ed894368
+0x008 Flags : _MMSUPPORT_FLAGS
+0x00c PageFaultCount : 0xb7
+0x010 PeakWorkingSetSize : 0xbd
+0x014 WorkingSetSize : 0xbd
+0x018 MinimumWorkingSetSize : 0x32
+0x01c MaximumWorkingSetSize : 0x159
+0x020 VmWorkingSetList : 0xc0883000 _MMWSL
+0x024 WorkingSetExpansionLinks : _LIST_ENTRY [ 0x864b2a9c - 0x8649323c ]
+0x02c Claim : 0
+0x030 NextEstimationSlot : 0
+0x034 NextAgingSlot : 0
+0x038 EstimatedAvailable : 0
+0x03c GrowthSinceLastEstimate : 0xb7
4)檢視VmWorkingSetList
指令:dt _MMWSL 0xc0883000
nt!_MMWSL
+0x000 Quota : 0
+0x004 FirstFree : 0x1e
+0x008 FirstDynamic : 0xa
+0x00c LastEntry : 0x217
+0x010 NextSlot : 7
+0x014 Wsle : 0xc0883cfc _MMWSLE //實體頁起始位址
+0x018 LastInitializedWsle : 0x4c0 //實體頁個數
+0x01c NonDirectCount : 0x33
+0x020 HashTable : 0xc0a84000 _MMWSLE_HASH
+0x024 HashTableSize : 0x200
+0x028 NumberOfCommittedPageTables : 2
+0x02c HashTableStart : 0xc0a84000 Void
+0x030 HighestPermittedHashAddress : 0xc0e00000 Void
+0x034 NumberOfImageWaiters : 0
+0x038 VadBitMapHint : 0x16
+0x03c UsedPageTableEntries : [1536] 0x34
+0xc3c CommittedPageTables : [48] 1
5)檢視最後一個成員
指令:dd 0xc0883cfc L4c2