前言
虛擬內存算是操作系統(tǒng)中比較重要的一部分了,內容也很多,早在看操作系統(tǒng)相關書籍的時候就有想要總結這一部分,但是功力不夠,總感覺串不起來;經(jīng)過秋招這幾個月對基礎知識的回顧,感覺對虛擬內存這一部分有了自己的一個認識和體系,遂趁這個機會述以成文。
本文首發(fā)自博主個人博客:虛擬內存
正文
一. 背景
在計算機硬件體系結構中,總有這樣一種規(guī)律:性能越好,價格越高;為了中和性價比,在計算機硬件體系中多采用逐級緩存的結構,通過軟件算法實現(xiàn)訪問性能與價格成本的平衡,這在計算機的存儲體系中體現(xiàn)的尤為明顯。
1.1 DRAM vs SRAM
DRAM:動態(tài)隨機訪問存儲器;價格低,訪問速度較慢,耗電量較大,一般用于做主存。
SRAM:靜態(tài)隨機訪問存儲器;價格高,訪問速度快,耗電量低,一般用于做高速緩存。
1.2 存儲器層次結構
如上圖,存儲器的層次結構實際上是一個金字塔形狀,從上到下,表示價格越來越低,容量越來越大;從上到下依次是:寄存器,L1,L2,L3三級高速緩存,主存,磁盤緩存,網(wǎng)絡緩存。存儲器的層次結構實際上也是一個逐級緩存的結構,其中,虛擬內存主要作用于主存與磁盤緩存之間,負責主存與磁盤之間的頁面交換。
二. 虛擬內存的目的
虛擬內存有三個目的:
將主存視為磁盤的高速緩存,在主存中只保留活動區(qū)域,提高主存利用率
為進程提供統(tǒng)一的地址空間,簡化內存管理
保護進程地址空間不被其他進程破壞
虛擬內存如何達到這三個目的,將在后文講解。
三. 虛擬內存的原理
3.1 基本概念
頁表:可以理解為位于主存中的一個大數(shù)組,由頁表項組成
頁表項:頁表的基本組成單元,頁表項分為兩個部分:標志位和地址位
虛擬頁:主存與磁之間的基本傳送單元,磁盤地址空間被視為一個個的虛擬頁
物理頁:緩存在主存中的實際單元
3.2 尋址的基本過程
因為頁表其實也是很占內存空間的,所以實際中會采用多級頁表和動態(tài)創(chuàng)建頁表的方式來減小頁表大小,這里為了方便了解尋址的整體過程,就以單級頁表為例;另外,頁表項的高速緩存這里也沒有考慮,高速緩存將在下一節(jié)介紹。
主存中有一個頁表,頁表由頁表項組成,將虛擬頁映射到物理頁;處理器(CPU)進行一次尋址的過程是:處理器生成一個虛擬地址,交給MMU(地址翻譯器)進行地址翻譯,MMU將虛擬地址轉換為頁表索引,然后去主存中查找對應的頁表項,如果主存中緩存該虛擬頁,則主存將虛擬頁對應的頁表項傳送給MMU,之后MMU從頁表項計算出物理地址送給主存,主存將物理地址對應的數(shù)據(jù)通過數(shù)據(jù)總線送給處理器;如果主存中沒有緩存虛擬頁對應的物理頁,則觸發(fā)一次缺頁異常,由主存從磁盤換取所需虛擬頁之后,再次執(zhí)行導致缺頁的指令。
如下圖所示:摘自《深入理解計算機系統(tǒng)》
3.3 頁表緩存
上文中提過,相比于 L1,L2,L3 三級高速緩存,主存的訪問速度還是很慢的( DRAM 比 SRAM 要慢約十多倍,磁盤比 DRAM 要慢約十萬多倍),所以如果每次進行尋址的時候,都按照上述過程,先去主存查找頁表項,然后再去主存取對應的物理頁,那么,即使每次頁面都命中的情況下,每次尋址也需要兩次的 DRAM 訪問(主存訪問),如果算上缺頁異常與主存與磁盤的頁面替換,耗費的時間將更多。
為了加速 MMU 地址翻譯的過程,會將頁表項緩存到 TLB(TLB 見后補充解釋) 和 L1 級高速緩存中,因此上述 MMU 進行地址翻譯的過程就變成了:MMU 根據(jù)虛擬地址從 TLB 中查找頁表項,如果找到,則直接進行后續(xù)物理地址生成;如果 TLB 未命中,則 MMU 從 L1 級高速緩存中查找對應的頁表項,如果命中,則將該頁表項緩存在 TLB 中并進行下一步,否則,繼續(xù)從主存中查找頁表項。
TLB:TLB 是一個在 MMU 中的高速緩存,用于緩存頁表項;如果 TLB 命中,那么所有的地址翻譯都是在芯片上的 MMU 中完成的,因此非常快。
如下圖所示:摘自《深入理解計算機系統(tǒng)》
3.4 地址翻譯的細節(jié)
3.4.1 從 TLB 查找頁表項
處理器生成的虛擬地址如下:
TLB 中每一行都保存著一個由單個頁表項組成的塊,用于組選擇和行匹配的索引和標記字段是從虛擬地址中的虛擬頁號(VPN)中提取出來的,如果 TLB 有 T = 2^t
個組,那么 TLB 索引(TLBI)是由 VPN 的 t 個最低位組成的,而 TLB 標記(TLBT)是由 VPN 中剩余的位組成的。
更多關于 TLB 查找頁表項的細節(jié)可參見: https://www.cnblogs.com/alantu2018/p/9000777.html
3.4.2 從主存中查找頁表項
如下圖:
虛擬地址由兩部分組成:虛擬頁號和虛擬頁偏移量;虛擬頁號可以簡單的視為頁表索引,如:根據(jù)VPN 0 選擇頁表項0,根據(jù) VPN 1 選擇頁表項1,依次類推。
3.4.3 從頁表項生成物理地址
仍如上圖:
可以看出,物理地址最終由兩個部分組成:低位是虛擬地址的另一部分,即虛擬頁偏移量,高位是頁表項的另一部分(頁表項還有一部分是標志位,上文介紹過)。
另外,根據(jù)上圖,還可以看出MMU是如何根據(jù)頁表項判斷虛擬頁是否在主存中有對應的物理頁的:上文中說過,頁表項分為兩部分,其中一部分是一個標志位(即途中的有效位),上圖也說的很清楚了,如果有效位為 0 ,說明虛擬頁對應的物理頁還為被緩存在主存中(缺頁),否則,說明命中。
3.5 頁表優(yōu)化
上文提到過,頁表占據(jù)的內存空間也是可觀的;對于一個 32 位的地址空間,4KB 的頁面和一個 4 字節(jié)的頁表項,即使應用所引用的只是虛擬地址空間中很小的一部分,也總是需要一個 4MB 的頁表常駐內存。為了優(yōu)化頁表占用的內存空間,實際中常采用多級頁表。
多級頁表的基本思路就是,增大單個頁表項所能映射的虛擬頁的大小,即進行粒度更大的映射(對于常駐內存的頁表來說),如:之前一個頁表項只能映射 4KB 的虛擬頁,如果一個頁表項能映射 4MB 的虛擬頁的話,頁表的大小也會相應的減小很多。
另外,多級頁表還支持動態(tài)創(chuàng)建子級頁表,即常駐內存的只有粒度最大的一級頁表,二級頁表等子級頁表不需要常駐內存,在進行地址翻譯時動態(tài)創(chuàng)建即可。
四. 局部性原理與內存抖動
MMU 進行地址翻譯以及缺頁時進行頁面替換的算法在很大程度上都依賴于局部性原理。程序的局部性原理意思是,程序上次用到的數(shù)據(jù)和代碼,在下次訪問時很可能也會用到;因此將下次很可能會用到的數(shù)據(jù)緩存在訪問速度更快的高速緩存中,將比較可觀的提升程序性能。
比較常見的頁面替換算法是:LRU 算法,即最近最少使用算法,以及其他更多頁面置換算法可參見: https://www.cnblogs.com/dolphin0520/p/3749259.html
內存抖動的意思是,處理器進行數(shù)據(jù)訪問時,不斷產(chǎn)生缺頁中斷,不斷進行頁面置換,造成程序運行緩慢。出現(xiàn)內存抖動一般有兩個原因:一個是頁面置換算法的缺陷,差的頁面置換算法通常會導致頁面命中率的降低,造成頻繁的缺頁中斷與頁面置換;另一個也可能與我們自己寫的程序有關。
五. 虛擬內存與進程
本文開始講虛擬內存的目的時,提到了虛擬內存對于進程的兩個目的:
- 為進程提供統(tǒng)一的地址空間,簡化內存管理:
操作系統(tǒng)為進程分配地址空間時,由于是通過虛擬內存進行虛擬頁與物理頁的映射,所以,對于進程而言,物理內存在地址空間上可以是不連續(xù)的(另外,這里還想提一點的是,這種不連續(xù)的映射,可以減少內存碎片與不同進程數(shù)據(jù)的共享,即通過虛擬內存將多個進程映射到同一虛擬頁即可實現(xiàn)進程間數(shù)據(jù)共享);同時,對于每一個進程而言,其地址空間都是由 0 開始往高地址增長(因為有 MMU 進行地址翻譯)
- 保護進程地址空間不被其他進程破壞:
進程在通過虛擬內存進行數(shù)據(jù)訪問時,虛擬內存可以添加一些權限校驗,防止進程間數(shù)據(jù)相互訪問。
六. 參考
- 《深入理解計算機系統(tǒng)》