Windows記憶體管理

來源:互聯網
上載者:User

標籤:設定檔   體會   dir   定址   方法   32位   布局   16進位   讀寫   

<<這不是原創,是老文,Pankaj Garg寫的,看後翻譯了一下,原文可以在http://www.intellectualheaven.com/找到。>>

1 介紹
Windows 32位 x86 作業系統最多能訪問4GB的實體記憶體。這是因為處理器的定址匯流排是32條(我們常說32位),能夠訪問的儲存單位的範圍是從0x00000000到0xFFFFFFFF,即4GB。Windows同樣允許每個進程擁有自己的4GB邏輯地址空間。4G的邏輯地址空間中,可供使用者操作的只有低位的2GB(是在使用者模式(user mode)下可操控的),高位的2GB被windows核心模式(kernel mode)霸佔了。
有人可能要問了,我機器總共沒有幾G記憶體,一個進程就可控4GB,那幾個進程還不打起來。。。
好問題,為了實現這個功能,windows採用了x86處理器(386及其後續的處理器)的一個功能,叫做分頁Paging。
分頁機制引入了邏輯地址這個概念,它允許軟體,或進程,使用邏輯地址,而不是物理地址。處理器的分頁單元能夠透明的將邏輯地址轉換為物理地址。基於這個機制,windows實現了讓每個進程擁有4GB邏輯空間的夢想。
想瞭解更多,我們先要看看x86的分頁機制是如何工作的。

2 x86 處理器的分頁機制
x86將物理地址空間(或實體記憶體)分為4KB的小塊,稱為記憶體頁Page。
如此算來,4GB的記憶體就有1Mega(1024x1024)4KB頁了。處理器使用二級索引結構來管理這1Mega記憶體頁。你可以想象成一個1024x1024的二維矩陣。
一維叫做頁目錄Page Directory,二維叫做頁表Page Table。
首先我們建立一個頁目錄包含1024項Entry,每一項指向一個頁表,這樣我們就有1024個頁表。
每個頁表也有1024項Entry,每一項指向4KB頁。如所示:

每一個頁目錄的項Page Directory Entry(簡稱PDE)實際上是一個4byte的指標,指向一個頁表Page Table。同樣,每個頁表項Page Table Entry(簡稱PTE)也是一個4byte的指標,指向4KB的實體記憶體地址。
因此我們需要4MB來構造這個二級索引結構來管理1024PDE,每個PDE包含1024PTE,即4 x 1024 x 1024 bytes。

綜上所述,整個記憶體空間被分為4KB的頁。因此當一個PDE或者PTE被使用時,它的高20位指向一個4KB的記憶體頁,低12位用來表示頁保護資訊和其它的一些內部資訊(OS的一些函數會使用)。高20位所表示的實際實體記憶體被稱為頁面號Page Frame Number(簡稱PFN)。

3 windows 頁表管理
在windows系統中,每個進程都擁有自己的頁目錄和頁表,即Windows為每個進程分配了4MB的空間來維護這個表。
當一個進程被建立時,頁目錄PD的每個項都指向頁表PT的物理地址。
頁表PT的每個項可以是有效或無效的,有效PTE指向分配給進程的4KB頁實體記憶體。
無效的PTE會被設定成特殊位來表示其無效,我們稱它們為無效PTE。
當進程要求記憶體時,這些PTE就被設定成分配的實體記憶體頁。
這裡有一件事需要強調,對於進程來說,它不知道實體記憶體的任何細節,它只使用邏輯地址。至於如何將邏輯地址映射到物理地址,這個是由Windows記憶體管理和處理器來完成的。

頁目錄PD的實體記憶體被稱為頁目錄基本地址Page Directory Base address(簡稱PDBA)。這個頁目錄基本地址儲存在一個特殊的CPU寄存器CR3(在x86)。當環境切換時,windows會重設CR3的值並讓其指向當前進程的PDBA。這樣,每個進程都能得到自己的4GB實體記憶體空間了。當然,同一時刻,系統所有進程的總的記憶體配置不可能超過RAM+pagefile的大小,但上述的機制可以允許windows給每個進程自己獨立的4GB邏輯(或者虛擬)地址空間。我們稱其為虛擬位址空間是因為即使進程有整個可用的4GB地址空間,它也只能使用配置給它的記憶體。當一個進程試圖訪問沒有配置的記憶體位址時,系統會給出一個違法訪問的錯誤,因為對應的PTE指向的是一個無效值。
此外,進程要求的記憶體大小不能超過當前系統可配置記憶體的大小。

將邏輯記憶體與實體記憶體分離的方法有許多優點,一個進程可以擁有4GB的線性空間,因此程式員無需擔心像Dos時代的記憶體片段問題。它還允許windows運行多個進程彼此使用同一機器上的實體記憶體而不用擔心A進程訪問到B進程的地址空間(除非A,B進程使用一些共用記憶體)。所以,一個進程不可能讀寫另一個進程的記憶體。

邏輯地址到物理地址的轉換是由處理器完成的。一個32位的邏輯地址被分成所示的3部分。

處理器首先根據CR3找到頁目錄的物理地址,然後由邏輯地址的前10位來索引對應的PDE,接著的10位來索引頁表的PTE,從而得到PTE指向的4KB實體記憶體頁。邏輯地址的低12位用來指向記憶體頁中具體的位置,相當於頁內的一個offset。

4 記憶體保護
windows對所有進程提供記憶體保護,例如一個進程不能訪問其他進程的記憶體。這個確保了系統中同時幾個進程友好共存。那麼Windows是如何做到的呢:
每個進程的PTE中只存放分配給這個進程的實體記憶體地址。這保證了進程無法訪問不屬於自己的記憶體。
流氓進程(原文寫的是a rouge process,rouge是胭脂,口紅的意思,實在想不通,估計可能是a rogue process)可能試圖修改它的頁表來訪問其它進程的實體記憶體。為了防止這種流氓行為,windows將頁表存放在核心態,即高位的2GB記憶體空間。這樣以來,一個使用者程式就無法訪問或修改頁表。當然,一個核心態的驅動程式可以做這種“流氓”行為,因為一旦一個程式運行在核心態,就相當於擁有了整個系統的許可權。下一節會具體解釋這一點。

5 windows 邏輯記憶體布局
windows將邏輯地址空間的低位2GB(或者3GB,通過設定boot.ini可以達到)設定為使用者態,高位的2GB(或1GB)給windows核心態。在核心態中,windows為頁表和頁目錄保留了從0xC0000000到0xC03FFFFF的空間。每個進程的頁表都在0xC0000000的邏輯地址,頁目錄在0xC0300000的邏輯地址。邏輯記憶體的布局如所示:

你可以用windows核心態調試器kd或者windbg來證實這個(參考!pte和!vtop調試指令)。頁目錄的物理地址存放在CR3.從0xC0300000開始的1024個地址表示了PDE。每個PDE佔用4個位元組的地址指標指向一個頁表。每個頁表有1024個項,每個項存放著4位元組物理地址指向4KB實體記憶體頁或者無效項的標識符。

那麼為什麼windows用0xC0000000和0xC0300000的邏輯地址來存放頁表和頁目錄呢?
windows要將頁表和頁目錄放在核心態,不是0x80000000(2GB的高位相鄰地址)就行了嗎。
。。。對,但是使用者程式要求更多的記憶體來實現自己的大型程式。。。於是3GB模式登場了!cool!
使用者可以編輯一個特殊的設定檔boot.ini來開啟3GB設定,這樣windows允許一個使用者態程式可以控制低位的3GB記憶體。而0xC0000000則是3GB的高位相鄰地址。所以我估計這就是頁表和頁目錄選址的依據。僅供參考,具體請參看Windows文檔。。。當然還有一些其他的重要因素決定了頁表和頁目錄在記憶體中的布局。為了看得更明白些,我偽造了一個進程並畫了一張頁表,高亮一些頁表項。注意,每個項的大小是4位元組。P_PT表示頁表的物理地址。

PDB表示該進程的頁目錄基地址。它表示該進程0xC0300000邏輯地址對應的物理地址。這個值儲存在CR3中。注意,windows只能使用邏輯地址來訪問任何記憶體,包括頁目錄,因此要訪問頁表和頁目錄,必須要在頁目錄中保持一些回訪性息如PDB。上面頁表顯示的物理地址項對每個進程都不同,但是每個進程都有自己的PDB項存放在頁目錄0x300的地方。

下面我們試著將4個不同邏輯地址轉換為物理地址,來體會一下PDB項的重要性,以及頁表布局和地址轉換如何工作。
我們將要轉換的地址是:0x2034AC54,0xC0000000,0xC0300000,0xC0300000[0x300]即0xC030C00。
第一個地址是普通的使用者態進程的邏輯地址,第二個地址是邏輯地址空間中第一個頁表的第一個邏輯地址,第三個地址是頁目錄基地址的邏輯地址,第四個地址是一個特殊項的邏輯地址。
假設CR3指向一個物理地址為0x13453###的記憶體。 前面講到,低12位用來存放頁保護資訊和OS需要的其他資料,這與我們當前的主題無關,因此將其屏蔽為###。高20位表示頁面號PFN是4KB對齊頁的物理地址。PFN對應真正的物理地址是0x13453000。讓我們做如下的地址轉換:
      1. 0x2034AC54
            我們把0x2034AC54分成三部分0010000000 1101001010 110001010100
            高10位0010000000是頁目錄的索引。轉成16進位是0x080。
            從CR3得到也目錄的物理地址是0x13453000,邏輯地址是0xC0300000。
            因此0xC0300000[0x080]可以得到頁表的物理地址P_PT。從上面的頁表可以知道其邏輯地址是0xC00001000(物理地址是0x45045000)。現在我們看接著的10位1101001010(即0x34A)為頁表的索引。
            地址0xC00001000[0x34A]可以得到4KB頁的物理地址,從上表可以得到為0x34005000。
            最後的12位110001010100(即0xC54),是相對於4KB頁記憶體起始位置的位移。所以最終的物理地址是0x34005C54。
剩下的3個交給讀者了。一旦你完成了,你就能明白為什麼PDB要存在0x300的位置。

我也是讀者,做一個吧。
      2. 0xC0000000 
            同樣我們把0xC0000000分成三部分1100000000 0000000000 0000000000 
            高10位1100000000是頁目錄的索引。轉成16進位是0x300。 
            從CR3得到也目錄的物理地址是0x13453000,邏輯地址是0xC0300000。 
            因此0xC0300000[0x300]可以得到頁表的物理地址P_PT。從上面的頁表可以知道其邏輯地址是PDB的地址0xC03000000(物理地址是0x13453000),還在頁目錄裡,於是再查0xC0300000[0x000]項的值,是0xC0000000(物理地址是0x6A078000)。現在我們看接著的10位0000000000(即0x000)為頁表的索引。 
            地址0xC00000000[0x000]可以得到4KB頁的物理地址,從上表可以得到為0x10480000。
            繞了一圈,結論是頁表中的值存放的肯定就是對應的4KB頁的物理地址。
<<2009-10-10 完>>

http://www.cnblogs.com/Kratos/archive/2009/09/09/1563624.html

Windows記憶體管理

相關文章

聯繫我們

該頁面正文內容均來源於網絡整理,並不代表阿里雲官方的觀點,該頁面所提到的產品和服務也與阿里云無關,如果該頁面內容對您造成了困擾,歡迎寫郵件給我們,收到郵件我們將在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.