虛擬存儲系統是指什么 虛擬存儲( 二 )


當CPU遇到缺頁時,會觸發缺頁異常 。缺失頁面異常將控制轉移到操作系統內核,然后調用內核中的缺失頁面異常處理程序,該程序將選擇一個受害頁面 。如果犧牲頁被修改過,內核會先把它拷貝回硬盤(用回寫機制代替直接寫也是為了盡量減少對硬盤的訪問次數),然后把虛擬頁覆蓋到犧牲頁的位置,更新PTE 。
當頁面錯誤異常處理程序返回時,它將重新啟動導致頁面錯誤的指令,這將向MMU重新發送導致頁面錯誤的虛擬地址 。既然已經成功處理了缺頁異常,那么最終的結果就是頁面命中并獲得物理地址 。
這種在硬盤和內存之間轉移頁面的行為稱為分頁:頁面從硬盤切換到內存,從內存切換到硬盤 。當異常發生時,將頁面交換到內存中的策略稱為請求分頁 。所有現代操作系統基本上都使用按需分頁策略 。
虛擬內存和CPU緩存(或者其他使用緩存的技術)一樣,依賴于局部性原則 。雖然處理缺頁會消耗大量的性能(畢竟還是要從硬盤中讀取),而且程序在運行過程中引用的不同虛擬頁面的總數可能會超過物理內存的大小,但是局部性原理保證了程序在任何時候都會傾向于工作在一個很小的活動頁面集上,這個頁面集就是所謂的工作集 。根據空之間的局部性原理(被訪問過的內存地址及其周圍的內存地址將有很大的機會再次被訪問)和時間局部性原理(被訪問過的內存地址稍后將有很大的機會再次被訪問),只要工作集緩存在物理內存中,下一個地址轉換請求就有很大的機會在其中,從而減少額外的硬盤流量 。
如果一個程序沒有好的局部性,就會使工作集的大小不斷擴大,直到超過物理內存的大小 。這個時候程序會產生一種狀態叫做thrashing,頁面會不斷的換入換出 。這么多倍的硬盤讀寫開銷,性能自然會“慘不忍睹” 。所以,要想寫出高性能的程序,首先要保證程序的時間局部性和空局部性 。
多級頁面表到目前為止,我們只討論了一頁表,但是在實際環境中,virtual 空之間的地址是非常大的(32位系統的地址空之間有2^32 = 4GB,更不用說64位系統了) 。在這種情況下,使用單頁表顯然是低效的 。
常見的方法是使用分層頁表 。假設我們的環境是一個32位虛擬地址空,其形式如下:
虛擬地址空分為4KB頁,每個PTE為4字節 。
內存的前2K頁分配給代碼和數據 。
接下來的6K頁尚未分配 。
接下來的1023頁不分配,下一頁分配給用戶棧 。
下圖顯示了為這個虛擬地址空(實際情況下有四級或四級以上)構建的二級頁表的層次結構 。一級頁表的每個PTE(1024個PTE剛好覆蓋4GB的虛擬地址空,每個PTE只有4個字節,所以一級頁表和二級頁表的大小和一個頁的大小完全一樣,都是4KB)負責每個PTE 。輔助頁表中的每個PTE負責映射一個4KB的虛擬內存頁 。

這種結構看起來像B樹,這種分層結構有效地降低了內存需求:
如果一級頁表的PTE是空,那么對應的二級頁表將不存在 。這代表了巨大的潛在節省(對于一個普通的程序,大多數虛擬地址空將是未分配的) 。
只有一級頁表總是需要緩存在內存中,這樣虛擬內存系統就可以在需要的時候創建、調入或調出二級頁表(只有經常使用的二級頁表才會緩存在內存中),減輕了內存壓力 。
地址翻譯的過程形式上,地址轉換是n元素的虛擬地址空中的元素和m元素的物理地址空中的元素之間的映射 。
下圖顯示了使用頁表進行MMU尋址的過程:

頁基址寄存器(PTBR)指向當前頁表 。具有n位的虛擬地址由兩部分組成,具有p位的虛擬頁面偏移量(VPO)和具有n-p位的虛擬頁面號(VPN) 。
MMU根據VPN選擇對應的PTE,例如VPN 0代表PTE 0,VPN 1代表PTE 1...因為物理頁面和虛擬頁面的大小相同,所以物理頁面偏移量(PPO)與VPO相同 。那么,只要將物理頁號、PTE中的PPN和虛擬地址中的VPO串聯起來,就可以得到對應的物理地址 。
多級頁表的地址轉換也是如此,只不過VPN需要分成多個段,因為有多個級別 。假設有一個K級頁表,將虛擬地址分為K個VPN和1個VPO,每個VPN i都是I級頁表的索引 。為了構造物理地址,MMU需要訪問K個pte來獲得相應的PPN 。

TLB頁面緩存在內存中 。雖然與硬盤相比,內存的速度已經很快了,但它仍然落后于CPU 。為了防止每個地址轉換操作訪問內存,CPU使用緩存和TLB來緩存PTE 。
最壞的情況下(不包括頁面未命中),MMU需要訪問內存來獲取對應的PTE,代價大概是幾十到幾百個周期 。如果PTE恰好緩存在L1緩存中(如果L1丟失,將從L2查找,但我們將忽略多級緩沖區的細節),那么性能開銷將下降到一個或兩個周期 。然而,許多系統甚至需要消除如此小的開銷,TLB應運而生 。

推薦閱讀