解析Winndows 2000/XP物理内存管理

类别:编程语言 点击:0 评论:0 推荐:

解析Winndows 2000/XP物理内存管理

   物理内存是相对比较紧张的资源,合理利用将是一个操作系统的性能的关键。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有详细的统计功能,不过通过这一代码与我先前提供的文章,也能基本上明白上面这幅图之间复杂关系。

    /*
       For test purpose,I define the below constant,but no say 
       MmSubsectionBase and MmNonPagedPoolEnd are fixed in 
       Windows 2000 and Windows XP. They are initialized on system 
       boot phase by ntoskrnl and rely on the system physical memory size etc.
    */
    #define WIN2000_2195
    #ifdef WINXP_2600 
    #define MmSubsectionBase 0x80d21000
    #define MmNonPagedPoolEnd 0xffbe0000
    #endif
    #ifdef WIN2000_2195
    #define MmSubsectionBase 0x0
    #define MmNonPagedPoolEnd 0xffb7f000
    #endif

    #define MmPfnDatabase 0xffb7f000    //Please redefine it on your machine.
    #define MmNumberOfPhysicalPages 0x3f7d  //Please redefine it on your machine.

    /*
      Portion of nt!MiGetSubsectionAndProtoFromPte
      Get Subsection from restore pte(original pte) at PFN Database Entry
      disasm by WebCrazy([email protected]) athttp://webcrazy.yeah.net
     Thanks to wuzq([email protected]) for light!
    */

    unsigned int MiGetSubsectionAndProtoFromPte(int pte)
    {
       unsigned int subaddr;
       if(pte < 0){ 
          subaddr = MmSubsectionBase+(((pte & 0x1e) <<2) |  ((pte>>4) & 0x7ffff80)) ;
       }else{
          subaddr = MmNonPagedPoolEnd-(((pte & 0x1e) <<2) |  ((pte>>4) & 0xfffff80)) ;
       }
       return subaddr;
    }

    /* 
      I release memusage() to dump Control Area.
      Only mapped file control area were dump.
      Please see windbg !memusage command.
    */


    void memusage()
    {
         unsigned int *pfndatabase = MmPfnDatabase;
         unsigned int numberphys = MmNumberOfPhysicalPages;

         unsigned int restorepte,pfn=0,ppte,subsection;

         unsigned char flag=0;
         static unsigned int flagnum[8];
         static char *flagdesc[8]=
                {"Zeroed","Free","Standby","Modified","ModNoWrt","Bad","Active","Trans"};
         memset(flagnum,0,sizeof(flagnum));

         for(;pfn<numberphys;pfn++){
            flag = *(char *)((char *)pfndatabase+0xd);
            flag &= 0x07;
            flagnum[flag]++;
            pfndatabase+=0x18/0x04;
        }

        DbgPrint("\nMemUsage:\n");
        for(flag=0;flag<8;flag++)
             DbgPrint("%10s:%04d(%08dK)\n",flagdesc[flag],flagnum[flag],flagnum[flag]*4);


        pfndatabase = MmPfnDatabase;
        for(pfn=0;pfn<numberphys;pfn++){
            ppte=*((unsigned int *)(pfndatabase+0x1));
            restorepte=*((unsigned int *)(pfndatabase+0x4));
            flag = *(char *)((char *)pfndatabase+0xd);
            flag &= 0x07;

            if(ppte>=0xE1000000&&ppte<0xF0000000){
               subsection=MiGetSubsectionAndProtoFromPte(restorepte);
               DbgPrint("pfn:%04X,ppte:%08X,restorepte:%08X,subsection:%08X,ca:%08X,
                    flag:%10s\n",pfn,ppte,restorepte,subsection,
                    MmIsAddressValid((void *)subsection)?*(unsigned int *)subsection:
                    0x11111111,flagdesc[flag]);
            }
            pfndatabase+=0x18/0x04;
        }
    }

    本文只是基本上说明了Windows 2000/XP下物理内存的组织管理,对于restore pte,正向前面介绍的其实他还指向pagefile,未加以叙述,着实因为这部分内容还很多,看我自己学习的进程,我会另行介绍。需要感谢的是wuzq([email protected])给我提供的思路,才可能有我对此的一些粗浅的理解,再次感谢他。





网友对该文章的评论 网友: ksdgfaijgioajogi([email protected]) 发表于: 2004-10-28 16:38:05

我 草!!!  是人学的吗?!!   
你妈B啊!!!!

弄这么难的干什么?!!  操你妈! 网友: sdf(dsfds) 发表于: 2004-1-17 12:14:26

sdfdsf 网友: 匿名 发表于: 2004-1-9 14:50:41

高深阿! 网友: 匿名 发表于: 2003-3-19 20:21:08

解析Winndows 2000/XP物理内存管理
 
2003-3-17 15:44:06   webcrazy.yeah.net   WebCrazy   阅读次数: 74 
   物理内存是相对比较紧张的资源,合理利用将是一个操作系统的性能的关键。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有详细的统计功能,不过通过这一代码与我先前提供的文章,也能基本上明白上面这幅图之间复杂关系。

    /*
       For test purpose,I define the below constant,but no say 
       MmSubsectionBase and MmNonPagedPoolEnd are fixed in 
       Windows 2000 and Windows XP. They are initialized on system 
       boot phase by ntoskrnl and rely on the system physical memory size etc.
    */
    #define WIN2000_2195
    #ifdef WINXP_2600 
    #define MmSubsectionBase 0x80d21000
    #define MmNonPagedPoolEnd 0xffbe0000
    #endif
    #ifdef WIN2000_2195
    #define MmSubsectionBase 0x0
    #define MmNonPagedPoolEnd 0xffb7f000
    #endif

    #define MmPfnDatabase 0xffb7f000    //Please redefine it on your machine.
    #define MmNumberOfPhysicalPages 0x3f7d  //Please redefine it on your machine.

    /*
      Portion of nt!MiGetSubsectionAndProtoFromPte
      Get Subsection from restore pte(original pte) at PFN Database Entry
      disasm by WebCrazy([email protected]) athttp://webcrazy.yeah.net
     Thanks to wuzq([email protected]) for light!
    */

    unsigned int MiGetSubsectionAndProtoFromPte(int pte)
    {
       unsigned int subaddr;
       if(pte < 0){ 
          subaddr = MmSubsectionBase+(((pte & 0x1e) <<2) |  ((pte>>4) & 0x7ffff80)) ;
       }else{
          subaddr = MmNonPagedPoolEnd-(((pte & 0x1e) <<2) |  ((pte>>4) & 0xfffff80)) ;
       }
       return subaddr;
    }

    /* 
      I release memusage() to dump Control Area.
      Only mapped file control area were dump.
      Please see windbg !memusage command.
    */


    void memusage()
    {
         unsigned int *pfndatabase = MmPfnDatabase;
         unsigned int numberphys = MmNumberOfPhysicalPages;

         unsigned int restorepte,pfn=0,ppte,subsection;

         unsigned char flag=0;
         static unsigned int flagnum[8];
         static char *flagdesc[8]=
                {"Zeroed","Free","Standby","Modified","ModNoWrt","Bad","Active","Trans"};
         memset(flagnum,0,sizeof(flagnum));

         for(;pfn<numberphys;pfn++){
            flag = *(char *)((char *)pfndatabase+0xd);
            flag &= 0x07;
            flagnum[flag]++;
            pfndatabase+=0x18/0x04;
        }

        DbgPrint("\nMemUsage:\n");
        for(flag=0;flag<8;flag++)
             DbgPrint("%10s:%04d(%08dK)\n",flagdesc[flag],flagnum[flag],flagnum[flag]*4);


        pfndatabase = MmPfnDatabase;
        for(pfn=0;pfn<numberphys;pfn++){
            ppte=*((unsigned int *)(pfndatabase+0x1));
            restorepte=*((unsigned int *)(pfndatabase+0x4));
            flag = *(char *)((char *)pfndatabase+0xd);
            flag &= 0x07;

            if(ppte>=0xE1000000&&ppte<0xF0000000){
               subsection=MiGetSubsectionAndProtoFromPte(restorepte);
               DbgPrint("pfn:%04X,ppte:%08X,restorepte:%08X,subsection:%08X,ca:%08X,
                    flag:%10s\n",pfn,ppte,restorepte,subsection,
                    MmIsAddressValid((void *)subsection)?*(unsigned int *)subsection:
                    0x11111111,flagdesc[flag]);
            }
            pfndatabase+=0x18/0x04;
        }
    }

    本文只是基本上说明了Windows 2000/XP下物理内存的组织管理,对于restore pte,正向前面介绍的其实他还指向pagefile,未加以叙述,着实因为这部分内容还很多,看我自己学习的进程,我会另行介绍。需要感谢的是wuzq([email protected])给我提供的思路,才可能有我对此的一些粗浅的理解,再次感谢他。

本文地址:http://com.8s8s.com/it/it24317.htm