解析Windows 2000/XP进程工作集
生活随笔
收集整理的這篇文章主要介紹了
解析Windows 2000/XP进程工作集
小編覺得挺不錯的,現(xiàn)在分享給大家,幫大家做個參考.
| 解析Windows 2000/XP進程工作集 |
| ????在《解析Windows?2000/XP物理內(nèi)存管理》中我詳細的介紹了頁框數(shù)據(jù)庫(Page?Frame?Database)的概念,提到在物理內(nèi)存的組織與管理方面對于每個頁面系統(tǒng)都在頁框數(shù)據(jù)庫中保存一個結(jié)構(gòu),用于跟蹤頁面狀態(tài)等。但頁框數(shù)據(jù)庫并不能真正協(xié)調(diào)物理內(nèi)存的使用。我們知道,Windows是一個多任務(wù)的操作系統(tǒng),而物理內(nèi)存卻是一個相對貧乏的資源,為避免某個進程(或是系統(tǒng))耗盡這一資源,引入了工作集(WorkingSet)的概念。WorkingSet是內(nèi)存管理一個相當(dāng)重要的術(shù)語,在Windows?2000/XP中通常分為兩種即進程工作集與系統(tǒng)工作集,分別用于跟蹤各個進程與系統(tǒng)的物理內(nèi)存使用情況。由于終端服務(wù)的引入,另有一種工作集會話(Session)工作集,用于跟蹤各個Session使用物理內(nèi)存的情況。本文從進程工作集的內(nèi)部組織方式出發(fā),簡要闡述工作集在Windows?2000/XP中的組織與管理。 ????EPROCESS是描述進程的結(jié)構(gòu),所以從EPROCESS入手,肯定也能找到進程工作集的表示方式。實際上位于EPROCESS中的子結(jié)構(gòu)MMSUPPORT就是關(guān)于進程與內(nèi)存子系統(tǒng)相關(guān)的一些關(guān)鍵內(nèi)容,進程工作集自然也在此。對于早期的內(nèi)核版本這些內(nèi)容沒有集成至MMSUPPORT結(jié)構(gòu)中,而且各版本間MMSUPPORT的定義是不相同的,底下列出MMSUPPORT在Windows?XP?Build?2600?SP0中的定義(本文中所有結(jié)構(gòu)都可能只適用于這一版本): ????typedef?struct?_MMSUPPORT?{ ????????LARGE_INTEGER???LastTrimTime; ????????MMSUPPORT_FLAGS?Flags; ????????ULONG???????????PageFaultCount; ????????ULONG???????????PeakWorkingSetSize; ????????ULONG???????????WorkingSetSize; ????????ULONG???????????MinimumWorkingSetSize; ????????ULONG???????????MaximumWorkingSetSize; ????????PMMWSL??????????VmWorkingSetList; ????????LIST_ENTRY??????WorkingSetExpansionLinks; ????????ULONG???????????Claim; ????????ULONG???????????NextEstimationSlot; ????????ULONG???????????NextAgingSlot; ????????ULONG???????????EstimatedAvailable; ????????ULONG???????????GrowthSinceLastEstimate; ????}?MMSUPPORT,?*PMMSUPPORT; ????MMSUPPORT中PeakWorkingSetSize、WorkingSetSize、MinimumWorkingSetSize與MaximumWorkingSetSize分別表示此進程的工作集峰值、當(dāng)然工作集大小、允許工作集的最大值與最小值。性能監(jiān)視器(perfmon.msc)與任務(wù)管理器(taskmgr.exe)都可對這些數(shù)據(jù)進程跟蹤顯示。Win32?API?GetProcessWorkingSetSize(Ex)和SetProcessWorkingSetSize(Ex)在具有相應(yīng)PROCESS_QUERY_INFORMATION與PROCESS_SET_QUOTA權(quán)限后即能獲取或設(shè)置MinimumWorkingSetSize與MaximumWorkingSetSize等。 ????進程在建立時,進程工作集總為空的,CreateProcess等在建立進程過程中有責(zé)任初始化進程工作集。它會分配一個物理頁面,然后調(diào)用MiInitializeWorkingSetList初始化進程工作集。后者以剛建立的EPROCESS作為參數(shù)初始化我們上面提到的MMSUPPORT結(jié)構(gòu)。這里要提到一個很重要的成員VmWorkingSetList(結(jié)構(gòu)MMWSL),定義如下: ???+0x000?Quota????????????:?Uint4B ???+0x004?FirstFree????????:?Uint4B ???+0x008?FirstDynamic?????:?Uint4B ???+0x00c?LastEntry????????:?Uint4B ???+0x010?NextSlot?????????:?Uint4B ???+0x014?Wsle?????????????:?Ptr32?_MMWSLE ???+0x018?LastInitializedWsle?:?Uint4B ???+0x01c?NonDirectCount???:?Uint4B ???+0x020?HashTable????????:?Ptr32?_MMWSLE_HASH ???+0x024?HashTableSize????:?Uint4B ???+0x028?NumberOfCommittedPageTables?:?Uint4B ???+0x02c?HashTableStart???:?Ptr32?Void ???+0x030?HighestPermittedHashAddress?:?Ptr32?Void ???+0x034?NumberOfImageWaiters?:?Uint4B ???+0x038?VadBitMapHint????:?Uint4B ???+0x03c?UsedPageTableEntries?:?[768]?Uint2B ???+0x63c?CommittedPageTables?:?[24]?Uint4B ????效率上考慮,Windows?2000/XP均將這一結(jié)構(gòu)映射至一固定的虛擬內(nèi)存地址中。由內(nèi)核變量MmWorkingSetList指定,實際上MiInitializeWorkingSetList就是直接引用這個變量對MMSUPPORT結(jié)構(gòu)的VmWorkingSetList成員進行操作的。MmWorkingSetList位于內(nèi)核區(qū)域(在Windows?XP?Build?2600?Professional中為0xc0503000),通常內(nèi)核區(qū)域均是由所有進程共享的,但顯然MmWorkingSetList指定的WorkingSet情況對于每個進程都有不同的映射,即具有不同的內(nèi)容,這與進程頁目錄或是頁表一樣。后者我在《小議Windows?NT/2000分頁機制》中詳細的做過測試。 ????因為進程WorkingSet是用于描述進程使用物理內(nèi)存的情況,換句話說位于WorkingSet中的頁面均位于物理內(nèi)存中(沒有被置換到pagefile.sys中等),所以訪問這些頁面均不會導(dǎo)致Page?Fault。我們可以使用VirtualLock將頁面置入進程工作集中。反過來想,系統(tǒng)如何知道某一頁面(使用虛擬頁面地址),針對這一進程是否存在于工作集中呢?粗粗瀏覽一下上面給出的MMWSL的定義,就知道Windows?2000/XP使用哈希表(HashTable)來組織這些頁面。HashTable具有快速檢索的特點,正好適合于WorkingSet頻繁訪問的特點。另一個例子是系統(tǒng)全局命名內(nèi)核的組織,詳見《剖析Windows?NT/2000內(nèi)核對象組織》。與Windbg提供dump全局命令內(nèi)核對象的!object命令一樣,Windbg提供!wsle用于dump進程工作集。例如: ????kd>?!wsle?7 ????Working?Set?@?c0503000 ????????FirstFree:??????469??FirstDynamic:??????????7 ????????LastEntry??????46c??NextSlot:?????????4??LastInitialized??????658 ????????NonDirect??????145??HashTable:?c06f4000??HashTableSize:???????400 ????Reading?the?WSLE?data... ????.. ????Virtual?Address??????Age????Locked??ReferenceCount ????????c0300203??????????0????????1????????1 ????????c0301203??????????0????????1????????1 ????????c0502203??????????0????????1????????1 ????????c0503203??????????0????????1????????1 ????????c0504203??????????0????????1????????1 ????????c06f4203??????????0????????1????????1 ????????c06f5203??????????0????????1????????1 ????????c0505203??????????0????????1????????1 ????????c0506203??????????0????????1????????1 ????????77c47029??????????0????????0????????1 ??????????????????????????????. ??????????????????????????????. ??????????????????????????????. ????wsle命令只是將VmWorkingSetList的Wsle成員(MMWSLE指針)指向的數(shù)組的每個元素dump出(每個元素32bit)。windbg的!wsle命令獲得的結(jié)果中Virtual?Address列即Wsle的每一個32bit的內(nèi)容。如下windbg命令所示: ????kd>?dd?MmWorkingSetList?l?1???//當(dāng)前進程MMWSL結(jié)構(gòu)所在的地址,如本文前頭描述。 ????805467d0??c0503000 ????kd>?dd?c0503000?l?10??????????//MMWSL內(nèi)容 ????c0503000??000003b9?000003ba?00000007?000003b9 ????c0503010??00000004?c050369c?00000658?0000014c ???????????????????????-------- ???????????????????????????|_MMWSLE內(nèi)容(如上給出的MMWSL定義,MMWSLE是一個指針) ????c0503020??c06f4000?00000400?0000001a?c06f4000 ?????????????????|?????????|_HashTableSize(Uint4B)哈希表大小 ?????????????????|_HashTable(MMWSLE_HASH)地址(底下將會用到這兩個數(shù)值) ????c0503030??c0800000?00000000?0000005c?004d023a ????kd>?dd?c050369c?? ????//結(jié)果即上面wsle命令輸出的Virtual?Address列(WorkingSet ????//頻繁變動,如果有稍許不同可能是系統(tǒng)已經(jīng)更改過了)。 ????c050369c??c0300203?c0301203?c0502203?c0503203 ????c05036ac??c0504203?c06f4203?c06f5203?c0505203 ????實際上這里的每一個Virtual?Address,就像上所示的如c0300203不僅僅是Virtual?Address,因為WorkingSet是以頁面為單位的,所以這些32bit的內(nèi)容中有12bit用于其它用途。實際上在Windows?XP中這個32bit的內(nèi)容定義為MMWSLENTRY,具體為: ????Valid????????????:?Pos?0,?1?Bit ????LockedInWs???????:?Pos?1,?1?Bit ????LockedInMemory???:?Pos?2,?1?Bit ????Protection???????:?Pos?3,?5?Bits ????SameProtectAsProto?:?Pos?8,?1?Bit ????Direct???????????:?Pos?9,?1?Bit ????Age??????????????:?Pos?10,?2?Bits ????VirtualPageNumber?:?Pos?12,?20?Bits ????wsle命令也即根據(jù)這低12bit輸出WSLE的一些屬性:如Age與Locked。ReferenceCount則位于PFN中,具體請參閱《解析Windows?2000/XP物理內(nèi)存管理》。 ????整個結(jié)構(gòu)至此已經(jīng)比較明朗了,但是正像上面提到的WorkingSet訪問是非常頻繁的,在檢索指定虛擬地址的頁面是否在WorkingSet中還要依靠另一個重要的成員HashTable。既然通過HashTable,我們來給出HashFunction(有興趣想知道如何得到HashFunction的可像我一樣看看MiInsertWsle是如何實現(xiàn)的)。 ????((PVA?>>a)?&?0x3ffffc)?%?(HashTableSize-1) ????這里,PVA指頁面虛擬地址,而HashTableSize指當(dāng)前進程的WorkingSet哈希表的大小。對于給定的一個頁面,如何在WSLE數(shù)組中快速的檢索到這個頁面的數(shù)組下標呢?有了哈希表,當(dāng)然通過Hash表了。這樣描述還是比較抽象,我們以一個具體的例子說明問題:從上面wsle命令輸出結(jié)果,我們知道虛擬地址77c47000(77c47029那一行),未于MMWSLE的第十項(數(shù)組下標為9,即index為9),而這個進程的工作集HashTableSize值為0x400(這個值可能系統(tǒng)會在需要時通常MiGrowWsleHash更改),所以: ????((77c47029>>a)&0x3ffffc)?%?(0x400-1) ????值為0x9a,所以位于HashTable的第0x9a個Bucket中(以0開始),通過上面得到的HashTable地址c06f4000,找到第0x9a個bucket。而每個Bucket的大小呢?需要說明的是這個HashTable的每個Bucket如下定義(_MMWSLE_HASH): ????+0x000?Key??????????????:?Uint4B ????+0x004?Index????????????:?Uint4B ????即每個bucket為8個字節(jié),所以我們用如下kd命令得到結(jié)果: ????kd>?dd?c06f4000+9a*8?l?2 ????c06f44d0??77c47000?00000009 ????其Key值為77c47000,即虛擬地址,Index值為9,即驗證了上面windbg的wsle命令輸出結(jié)果。現(xiàn)在,對于WorkingSet的組織也已經(jīng)討論的差不多了,需要指出的是在Windows?XP中WorkingSet的設(shè)計遠比這討論的多很多內(nèi)容,比如WorkingSet的哈希表是可擴展的(通過MiGrowWsleHash),HashTable內(nèi)容的插入、更改、刪除,還有工作集修整(通過MiTrimWorkingSet)等等,特別是工作集修整,文章開頭提到工作集的一個主要作用合理利用物理內(nèi)存,避免某個進程(或是系統(tǒng))耗盡物理內(nèi)存,通過WorkingSet的最大、最小值與Quota指定的限額,限定物理內(nèi)存的使用。如果出現(xiàn)越出這樣的一個范圍或是物理內(nèi)存耗盡,則會使用工作集修整。Andrew?Tanenbaum的《Modern?Operating?Systems》介紹了多種工作集修整的算法,在單處理器中Windows?2000/XP中使用了更像LRU的時候算法(Clock?algorithm正像很多Unix系統(tǒng)實現(xiàn)一樣),你應(yīng)該看到上面輸出的Age的值吧。由于條件限制我只能在單處理器上實驗過。為了篇幅完整,我簡要介紹一下多處理器的情況:多處理中Windows?2000使用FIFO(First?In?First?Out)算法,但從我看到的Microsoft的一些介紹中,似乎Windows?XP/.Net?Server?2003在多處理中也使用LRU了,看來Windows的內(nèi)核是越來越完善了。 ????本文只介紹了進程工作集,對于系統(tǒng)工作集及Session工作集,大同小異,實際上我是在分析了三種工作集后,才開始著手寫這樣的一篇。這一些些的概念、結(jié)構(gòu)在自己的學(xué)習(xí)過程中不斷被發(fā)現(xiàn),也著實讓自己興奮不已,但我從來沒有看過任何關(guān)于這些結(jié)構(gòu)層次上的討論,錯誤之處,在所難免,敬請見諒,謝謝 |
總結(jié)
以上是生活随笔為你收集整理的解析Windows 2000/XP进程工作集的全部內(nèi)容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: [C++调试笔记]diag.cpp
- 下一篇: java信息管理系统总结_java实现科