分享
 
 
 

解析Windows 2000/XP进程工作集

王朝vc·作者佚名  2006-01-08
窄屏简体版  字體: |||超大  

解析Windows 2000/XP进程工作集

在《解析Windows 2000/XP物理内存管理》中我详细的介绍了页框数据库(Page Frame Database)的概念,提到在物理内存的组织与管理方面对于每个页面系统都在页框数据库中保存一个结构,用于跟踪页面状态等。但页框数据库并不能真正协调物理内存的使用。我们知道,Windows是一个多任务的操作系统,而物理内存却是一个相对贫乏的资源,为避免某个进程(或是系统)耗尽这一资源,引入了工作集(WorkingSet)的概念。WorkingSet是内存管理一个相当重要的术语,在Windows 2000/XP中通常分为两种即进程工作集与系统工作集,分别用于跟踪各个进程与系统的物理内存使用情况。由于终端服务的引入,另有一种工作集会话(Session)工作集,用于跟踪各个Session使用物理内存的情况。本文从进程工作集的内部组织方式出发,简要阐述工作集在Windows 2000/XP中的组织与管理。

EPROCESS是描述进程的结构,所以从EPROCESS入手,肯定也能找到进程工作集的表示方式。实际上位于EPROCESS中的子结构MMSUPPORT就是关于进程与内存子系统相关的一些关键内容,进程工作集自然也在此。对于早期的内核版本这些内容没有集成至MMSUPPORT结构中,而且各版本间MMSUPPORT的定义是不相同的,底下列出MMSUPPORT在Windows XP Build 2600 SP0中的定义(本文中所有结构都可能只适用于这一版本):

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分别表示此进程的工作集峰值、当然工作集大小、允许工作集的最大值与最小值。性能监视器(perfmon.msc)与任务管理器(taskmgr.exe)都可对这些数据进程跟踪显示。Win32 API GetProcessWorkingSetSize(Ex)和SetProcessWorkingSetSize(Ex)在具有相应PROCESS_QUERY_INFORMATION与PROCESS_SET_QUOTA权限后即能获取或设置MinimumWorkingSetSize与MaximumWorkingSetSize等。

进程在建立时,进程工作集总为空的,CreateProcess等在建立进程过程中有责任初始化进程工作集。它会分配一个物理页面,然后调用MiInitializeWorkingSetList初始化进程工作集。后者以刚建立的EPROCESS作为参数初始化我们上面提到的MMSUPPORT结构。这里要提到一个很重要的成员VmWorkingSetList(结构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均将这一结构映射至一固定的虚拟内存地址中。由内核变量MmWorkingSetList指定,实际上MiInitializeWorkingSetList就是直接引用这个变量对MMSUPPORT结构的VmWorkingSetList成员进行操作的。MmWorkingSetList位于内核区域(在Windows XP Build 2600 Professional中为0xc0503000),通常内核区域均是由所有进程共享的,但显然MmWorkingSetList指定的WorkingSet情况对于每个进程都有不同的映射,即具有不同的内容,这与进程页目录或是页表一样。后者我在《小议Windows NT/2000分页机制》中详细的做过测试。

因为进程WorkingSet是用于描述进程使用物理内存的情况,换句话说位于WorkingSet中的页面均位于物理内存中(没有被置换到pagefile.sys中等),所以访问这些页面均不会导致Page Fault。我们可以使用VirtualLock将页面置入进程工作集中。反过来想,系统如何知道某一页面(使用虚拟页面地址),针对这一进程是否存在于工作集中呢?粗粗浏览一下上面给出的MMWSL的定义,就知道Windows 2000/XP使用哈希表(HashTable)来组织这些页面。HashTable具有快速检索的特点,正好适合于WorkingSet频繁访问的特点。另一个例子是系统全局命名内核的组织,详见《剖析Windows NT/2000内核对象组织》。与Windbg提供dump全局命令内核对象的!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指针)指向的数组的每个元素dump出(每个元素32bit)。windbg的!wsle命令获得的结果中Virtual Address列即Wsle的每一个32bit的内容。如下windbg命令所示:

kd> dd MmWorkingSetList l 1 //当前进程MMWSL结构所在的地址,如本文前头描述。

805467d0 c0503000

kd> dd c0503000 l 10 //MMWSL内容

c0503000 000003b9 000003ba 00000007 000003b9

c0503010 00000004 c050369c 00000658 0000014c

--------

|_MMWSLE内容(如上给出的MMWSL定义,MMWSLE是一个指针)

c0503020 c06f4000 00000400 0000001a c06f4000

| |_HashTableSize(Uint4B)哈希表大小

|_HashTable(MMWSLE_HASH)地址(底下将会用到这两个数值)

c0503030 c0800000 00000000 0000005c 004d023a

kd> dd c050369c

//结果即上面wsle命令输出的Virtual Address列(WorkingSet

//频繁变动,如果有稍许不同可能是系统已经更改过了)。

c050369c c0300203 c0301203 c0502203 c0503203

c05036ac c0504203 c06f4203 c06f5203 c0505203

实际上这里的每一个Virtual Address,就像上所示的如c0300203不仅仅是Virtual Address,因为WorkingSet是以页面为单位的,所以这些32bit的内容中有12bit用于其它用途。实际上在Windows XP中这个32bit的内容定义为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命令也即根据这低12bit输出WSLE的一些属性:如Age与Locked。ReferenceCount则位于PFN中,具体请参阅《解析Windows 2000/XP物理内存管理》。

整个结构至此已经比较明朗了,但是正像上面提到的WorkingSet访问是非常频繁的,在检索指定虚拟地址的页面是否在WorkingSet中还要依靠另一个重要的成员HashTable。既然通过HashTable,我们来给出HashFunction(有兴趣想知道如何得到HashFunction的可像我一样看看MiInsertWsle是如何实现的)。

((PVA >>a) & 0x3ffffc) % (HashTableSize-1)

这里,PVA指页面虚拟地址,而HashTableSize指当前进程的WorkingSet哈希表的大小。对于给定的一个页面,如何在WSLE数组中快速的检索到这个页面的数组下标呢?有了哈希表,当然通过Hash表了。这样描述还是比较抽象,我们以一个具体的例子说明问题:从上面wsle命令输出结果,我们知道虚拟地址77c47000(77c47029那一行),未于MMWSLE的第十项(数组下标为9,即index为9),而这个进程的工作集HashTableSize值为0x400(这个值可能系统会在需要时通常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个字节,所以我们用如下kd命令得到结果:

kd> dd c06f4000+9a*8 l 2

c06f44d0 77c47000 00000009

其Key值为77c47000,即虚拟地址,Index值为9,即验证了上面windbg的wsle命令输出结果。现在,对于WorkingSet的组织也已经讨论的差不多了,需要指出的是在Windows XP中WorkingSet的设计远比这讨论的多很多内容,比如WorkingSet的哈希表是可扩展的(通过MiGrowWsleHash),HashTable内容的插入、更改、删除,还有工作集修整(通过MiTrimWorkingSet)等等,特别是工作集修整,文章开头提到工作集的一个主要作用合理利用物理内存,避免某个进程(或是系统)耗尽物理内存,通过WorkingSet的最大、最小值与Quota指定的限额,限定物理内存的使用。如果出现越出这样的一个范围或是物理内存耗尽,则会使用工作集修整。Andrew Tanenbaum的《Modern Operating Systems》介绍了多种工作集修整的算法,在单处理器中Windows 2000/XP中使用了更像LRU的时候算法(Clock algorithm正像很多Unix系统实现一样),你应该看到上面输出的Age的值吧。由于条件限制我只能在单处理器上实验过。为了篇幅完整,我简要介绍一下多处理器的情况:多处理中Windows 2000使用FIFO(First In First Out)算法,但从我看到的Microsoft的一些介绍中,似乎Windows XP/.Net Server 2003在多处理中也使用LRU了,看来Windows的内核是越来越完善了。

本文只介绍了进程工作集,对于系统工作集及Session工作集,大同小异,实际上我是在分析了三种工作集后,才开始着手写这样的一篇。这一些些的概念、结构在自己的学习过程中不断被发现,也着实让自己兴奋不已,但我从来没有看过任何关于这些结构层次上的讨论,错误之处,在所难免,敬请见谅,谢谢

 
 
 
免责声明:本文为网络用户发布,其观点仅代表作者个人观点,与本站无关,本站仅提供信息存储服务。文中陈述内容未经本站证实,其真实性、完整性、及时性本站不作任何保证或承诺,请读者仅作参考,并请自行核实相关内容。
2023年上半年GDP全球前十五强
 百态   2023-10-24
美众议院议长启动对拜登的弹劾调查
 百态   2023-09-13
上海、济南、武汉等多地出现不明坠落物
 探索   2023-09-06
印度或要将国名改为“巴拉特”
 百态   2023-09-06
男子为女友送行,买票不登机被捕
 百态   2023-08-20
手机地震预警功能怎么开?
 干货   2023-08-06
女子4年卖2套房花700多万做美容:不但没变美脸,面部还出现变形
 百态   2023-08-04
住户一楼被水淹 还冲来8头猪
 百态   2023-07-31
女子体内爬出大量瓜子状活虫
 百态   2023-07-25
地球连续35年收到神秘规律性信号,网友:不要回答!
 探索   2023-07-21
全球镓价格本周大涨27%
 探索   2023-07-09
钱都流向了那些不缺钱的人,苦都留给了能吃苦的人
 探索   2023-07-02
倩女手游刀客魅者强控制(强混乱强眩晕强睡眠)和对应控制抗性的关系
 百态   2020-08-20
美国5月9日最新疫情:美国确诊人数突破131万
 百态   2020-05-09
荷兰政府宣布将集体辞职
 干货   2020-04-30
倩女幽魂手游师徒任务情义春秋猜成语答案逍遥观:鹏程万里
 干货   2019-11-12
倩女幽魂手游师徒任务情义春秋猜成语答案神机营:射石饮羽
 干货   2019-11-12
倩女幽魂手游师徒任务情义春秋猜成语答案昆仑山:拔刀相助
 干货   2019-11-12
倩女幽魂手游师徒任务情义春秋猜成语答案天工阁:鬼斧神工
 干货   2019-11-12
倩女幽魂手游师徒任务情义春秋猜成语答案丝路古道:单枪匹马
 干货   2019-11-12
倩女幽魂手游师徒任务情义春秋猜成语答案镇郊荒野:与虎谋皮
 干货   2019-11-12
倩女幽魂手游师徒任务情义春秋猜成语答案镇郊荒野:李代桃僵
 干货   2019-11-12
倩女幽魂手游师徒任务情义春秋猜成语答案镇郊荒野:指鹿为马
 干货   2019-11-12
倩女幽魂手游师徒任务情义春秋猜成语答案金陵:小鸟依人
 干货   2019-11-12
倩女幽魂手游师徒任务情义春秋猜成语答案金陵:千金买邻
 干货   2019-11-12
 
推荐阅读
 
 
 
>>返回首頁<<
 
靜靜地坐在廢墟上,四周的荒凉一望無際,忽然覺得,淒涼也很美
© 2005- 王朝網路 版權所有