淺議Windows 2000/XP Pagefile組織管理

來源:互聯網
上載者:User

轉自:http://www.cnblogs.com/Sonic2007/archive/2008/07/08/1238167.html

任何時候系統記憶體資源相對磁碟空間來說都是相形見拙的。因為虛擬記憶體機制,使我們可以有相對豐富的地址資源(通常32bit的虛擬位址,可以有4G的定址空間),而這些資源對實體記憶體來說一般情況是總是綽綽有餘的。所以在現代作業系統中,總是在相對緊張時使用一些策略,如FIFO、LRU等將實體記憶體的一些頁面置入相對便宜的磁碟空間資源中。一般的UNIX系統,獨立使用一個分區,即swap partition。而這方面Windows只是使用普通的檔案,通常命名為pagefile.sys,位於各分區的根目錄中。由於受到用於pagefile的PTE的限制(PTE中使用4bit來識別操作的pagefile),所以Windows最多可以支援16個pagefile.sys。

    從上描述,pagefile.sys本身就是一個比較特殊的檔案,根據系統的情況它的大小是可擴充的,通常我們可以使用“控制台”的“系統”小Applet來設定。由於其特殊性,Windows在啟動階段會對每個pagefile.sys建立相應的FILE_OBJECT,並且設定SharedRead欄位為False,而且在System進程,每個FILE_OBJECT都分別有一個控制代碼指向,這樣即只允許系統自身對其操作,避免使用者對其進行刪除等誤操作。

    為了對pagefile.sys進行管理,Windows中有一個長度為16的數組,用於對pagefile.sys的組織。每個成員分別對應一個pagefile。這個數組由系統變數MmPagingFile指向,每個成員都是一個指向MMPAGING_FILE的結構,這個結構有如下的格式:

    +0x000 Size             : Uint4B
    +0x004 MaximumSize      : Uint4B
    +0x008 MinimumSize      : Uint4B
    +0x00c FreeSpace        : Uint4B
    +0x010 CurrentUsage     : Uint4B
    +0x014 PeakUsage        : Uint4B
    +0x018 Hint             : Uint4B
    +0x01c HighestPage      : Uint4B
    +0x020 Entry            : [2] Ptr32 _MMMOD_WRITER_MDL_ENTRY
    +0x028 Bitmap           : Ptr32 _RTL_BITMAP
    +0x02c File             : Ptr32 _FILE_OBJECT
    +0x030 PageFileName     : _UNICODE_STRING
    +0x038 PageFileNumber   : Uint4B
    +0x03c Extended         : UChar
    +0x03d HintSetToZero    : UChar
    +0x03e BootPartition    : UChar
    +0x040 FileHandle       : Ptr32 Void

通過這個結構,我們可以很容易的得到相應pagefile的使用方式(MaximumSize、MinimumSize、FreeSpace、CurrentUsage、PeakUsage,請參閱windbg的!vm命令),其對應的FILE_OBJECT等。另外通過FILE_OBJECT的DeviceObject與Vpb欄位,我們就可知道這個pagefile所處的分區及分區使用的檔案系統等等資訊。我們來詳細介紹一下Bitmap成員。

    Bitmap是一個RTL_BITMAP的結構,其定義在ntddk.h中:

    typedef struct _RTL_BITMAP {
        ULONG SizeOfBitMap;                     // Number of bits in bit map
        PULONG Buffer;                          // Pointer to the bit map itself
    } RTL_BITMAP;

    與頁框資料庫(Pfn Database)與虛擬記憶體(x86平台PAGE_SIZE 4k)一樣,Windows也將pagefile分割成4K一塊塊的大小,稱為一頁,每頁由Bitmap對應的1 bit指定狀態。1為佔用,0為空白閑。通過使用RtlFindClearBits或是RtlFindClearBitsAndSet等函數對Bitmap進行操作,尋找這些檔案的未用頁面。雖然Bitmap指明佔用狀態時,Windows常以4k為單位,但為了提高效能,Windows在一次寫pagefile的單位通常為64k(MmModifiedWriteClusterSize個頁)。還有MMMOD_WRITER_MDL_ENTRY,等我下面提及相關內容時再加以說明。

    先用windbg來消化一下上面的討論:

    kd> dd MmPagingFile l 10  //從輸出結果可以看出我的機子上設了兩個pagefile。
    80547020  80d2af80 feec1548 00000000 00000000
    80547030  00000000 00000000 00000000 00000000
    80547040  00000000 00000000 00000000 00000000
    80547050  00000000 00000000 00000000 00000000
    kd> dd @$p l 40   //第一個pagefile的情況。
    80d2af80  00006400 0000c800 00006400 00000c38
    80d2af90  000057c7 000057c7 00000000 00000000
    80d2afa0  feea1cb8 feea1c18 fecbb000 feddc428
            .
            .
            .

    kd> dd feddc428 l 4  //從上面給出的MMPAGING_FILE,很容易得到file object(Offset 0x2c)。
    feddc428  00700005 80ecf2f0 80ecf268 fee66c10

    kd> !devobj 80ecf2f0   //aFILE_OBJECT的結構在ntddk.h中給出,其第三個dword就是DEVICE_OBJECT。
    Device object (80ecf2f0) is for:
     HarddiskVolume2 \Driver\Ftdisk DriverObject 80d97030
    Current Irp 00000000 RefCount 1316 Type 00000007 Flags 00001150
    Vpb 80ecf268 Dacl e13d1484 DevExt 80ecf3a8 DevObjExt 80ecf490 Dope 80ecf210 DevNode 80d95bd0 
    ExtensionFlags (0000000000)  
    AttachedDevice (Upper) 80d954b8 \Driver\VolSnap
    Device queue is not busy.

    另外FILE_OBJECT的第四個dword(fee66c10)就是VPB結構,你使用!vpb分析分析,限於篇幅,我就不在這兒列出了。

    通過上面windbg的分析,我們已經基本上對pagefile有了一定的瞭解了,下面轉入記憶體子系列與IO子系統(調用FSD)對pagefile的組織管理。

    通常情況下,對於進程可見的永遠是虛擬位址,存取某個虛擬位址,對於不存在的地址(對於X86,即其PTE的P位為0),通過觸發硬體中斷(X86為int e),由軟體來對這些PTE進行解析,譬如原型PTE(我在《探究Windows 2000/XP原型PTE》中詳細介紹),或是過渡PTE(Transition PTE,某些頁面由於進程工作集修整等原因,成為可被使用的頁面,但這些頁面的內容當前對這些進程仍有效,可隨時重新使用,所以Windows使用Transition這個術語區別於純粹的Free或Zeroed列表,我在《解析Winndows 2000/XP實體記憶體管理》中提及PFN列表)等,而對於Page File,實際上也有一個對應的pte指向相應pagefile.sys,完成解析工作(MiResolvePageFileFault),處理分頁錯誤(通過IoPageRead,下面會介紹)。

    所以在繼續討論之前我們來說明一下Pagefile PTE,它的格式如下:

    Valid            : Pos 0, 1 Bit
    PageFileLow      : Pos 1, 4 Bits
    Protection       : Pos 5, 5 Bits
    Prototype        : Pos 10, 1 Bit
    Transition       : Pos 11, 1 Bit
    PageFileHigh     : Pos 12, 20 Bits

    對於Prototype PTE與Transition PTE,總有1bit用於識別相應的PTE,如上的Prototype欄位,但對於PageFile PTE,卻沒有對應的識別bit,實際上MiDispatchFault(由KiTrap0E調用),是在解析完Prototype PTE(MiResolveProtoPteFault)、Transition PTE(MiResolveTransitionFault)、還有MiResolveDemandZeroFault後,才調用MiResolvePageFileFault的,當然在MiResolveProtoPteFault處理過程中也是最後調用MiResolvePageFileFault的。

    假設我們存取一個當前駐留在pagefile中的頁面,通過MiDispatchFault,控制權轉到MiResolvePageFileFault後,他會根據PTE的PageFileLow來索引MMPAGING_FILE數組,即判斷這一頁面位於哪個pagefile.sys中,因為PageFileLow為4個bit,所以Windows最多可以支援16個pagefile.sys。這樣記憶體子系統根據這個索引從MmPagingFile中描述的頁檔案結構取出這個pagefile的FILE_OBJECT(上面介紹過)。加上PageFileHigh所指定的pagefile.sys的位移值,MiResolvePageFileFault通過返回一個值為0xC0033333的特殊NTSTATUS通知MiDispatchFault調用IoPageRead得到此頁面。IoPageRead的原型如下(定義於ntifs.h中):

    NTKERNELAPI
    NTSTATUS
    IoPageRead(
        IN PFILE_OBJECT FileObject,
        IN PMDL MemoryDescriptorList,
        IN PLARGE_INTEGER StartingOffset,
        IN PKEVENT Event,
        OUT PIO_STATUS_BLOCK IoStatusBlock
    ); 

    當然在調用IoPageRead之前,記憶體管理器必須分配一個物理頁面,必要的時候還要調用MiRemoveAnyPage騰出空間,然後調用MiInitializeReadInProgressPfn,將這一頁框置成ReadInProgress狀態,然後將IoPageRead所需要的MDL參數MemoryDescriptorList指向這一頁面。MDL的虛擬位址欄位也就是IoPageRead讀入的頁面映射的虛擬位址,也即滿足我們先前假設的分頁錯誤。

    IoPageRead實際上通過Allocate一個IRP,用DIRECT_IO的方式(即我們提供的MDL),然後設定一個Complete Routine,用於取消頁面讀取之前的ReadInProgress狀態,再通過IoCallDriver調用IO子系統調用對應的File System Driver(通常由FILE_OBJECT的VPB參數確定),至於FSD是如何讀取pagefile.sys的,這兒不加以討論,ntifs提供的fastfat的原始碼是學習的方向。

    需要指出的是IoPageRead是一個同步操作,即只有等待頁面讀完畢以後才可以往下處理。這也是MiDispatchFault只能運行於DISPATCH_LEVEL IRQL之下的主要原因。IoPageRead通過裝置分配的IRP的IRP_SYNCHRONOUS_PAGING_IO的標誌來實現同步的。另外他也設定了IRP_PAGING_IO、IRP_NOCACHE標誌,用於與FSD之間的特殊通訊要求。

    由於工作集修整等的需要,通過MiModifiedPageWriter(MPW)線程實行將某些頁面置入pagefile中。MPW使用MMPAGING_FILE結構的_MMMOD_WRITER_MDL_ENTRY類型的Entry進行操作,_MMMOD_WRITER_MDL_ENTRY不僅僅由MiModifiedPageWriter使用,他還要讓MiMappedPageWriter使用(用於Mapped file),所以_MMMOD_WRITER_MDL_ENTRY結構不僅函有MDL成員,還包含Control Area等等。限於篇幅,我不將其結構列出。MPW通過IoAsynchronousPageRead將頁面按前面說的一次MmModifiedWriteClusterSize個頁面寫入pagefile中。對於IoAsynchronousPageRead其使用的IRP flag是IRP_PAGING_IO與IRP_NOCACHE,說明他是非同步作業的。這也可從他的名字看出,區別於Windows提供的另一個相關過程IoSynchronousPageWrite,他是同步的。

    講到這兒,對於page file的組織管理的一些基本的印象應該是有的。最後需要指出的一點是,對於IoPageRead不僅僅是對於pagefile的,其也可以針對mapped file,還有MiModifiedPageWriter,要不是避免死結也不會區分出MiMappedPageWriter,實際上Windows內部記憶體管理器對於pagefile與mappedfile的管理使用是基本相同的,而FSD的處理也只是一點點的區別而已。所以結合我以前介紹的如Control Area等概念,對mapped file等的理解也是可以參照本文的。還有同樣的一句話,錯誤地方希望得到你的指點。

相關文章

聯繫我們

該頁面正文內容均來源於網絡整理,並不代表阿里雲官方的觀點,該頁面所提到的產品和服務也與阿里云無關,如果該頁面內容對您造成了困擾,歡迎寫郵件給我們,收到郵件我們將在5個工作日內處理。

如果您發現本社區中有涉嫌抄襲的內容,歡迎發送郵件至: info-contact@alibabacloud.com 進行舉報並提供相關證據,工作人員會在 5 個工作天內聯絡您,一經查實,本站將立刻刪除涉嫌侵權內容。

A Free Trial That Lets You Build Big!

Start building with 50+ products and up to 12 months usage for Elastic Compute Service

  • Sales Support

    1 on 1 presale consultation

  • After-Sales Support

    24/7 Technical Support 6 Free Tickets per Quarter Faster Response

  • Alibaba Cloud offers highly flexible support services tailored to meet your exact needs.