操作系統中的頁式內存管理

 戳藍字「TopCoder」關注我們哦!

編者注:操作系統中兩個重要的概念是CPU和內存,CPU管理相對來說比較"直男"一點,只顧着執行指令,最多忙到100%或者超頻執行;但對於內存來說,它是資源有限的,如果進程佔用內存較大甚至大於物理內存,並且要同時執行多個進程,這就涉及到內存管理。

1. 內存管理

理想情況下用戶對內存的期待是大容量、高速度和持久性,但是現實中卻是一個由緩存、主存、磁盤組成的內存架構,該架構中,緩存低容量、速度快但是成本高,主存中速度、中容量和中成本,磁盤就是大容量、持久性但是速度慢。

內存管理就是要對"用戶"提供一個統一的抽象,屏蔽緩存、主存和磁盤之間的差異,甚至感知不到它們的存在。用戶無需擔心程序是存儲在緩存、主存或者磁盤上,反正運行、輸出的結果都是一樣的,這種抽象就是通過虛擬內存來實現的。

操作系統中要同時執行多個進程程序,要保證它們之間互不干擾,也就是說一個進程不能訪問另一個進程的內存空間。程序中讀寫特定內存數據時,不能直接映射到物理內存,也就是說程序發出的內存地址和物理內存要是獨立的。綜上所述,內存管理的目標就是:

  • 地址保護:一個程序不能訪問另一個程序地址空間。

  • 地址獨立:程序發出的地址應與物理主存地址無關。

1.1. 虛擬內存

虛擬內存是操作系統發展史上一個重要的里程碑,虛擬內存的使用,避免程序直接和主存(物理內存)打交道,並且對緩存、主存和磁盤做了統一抽象,這樣程序就可以突破物理內存的大小限制,當然程序還是要受制於虛擬內存的大小限制的。

應用程序、虛擬內存和物理內存的關係如下:

程序中看到的內存地址是虛擬內存地址,程序讀寫內存時會被映射到實際的物理內存中,這個映射稱爲翻譯,這個翻譯工作是由MMU(內存管理單元)來完成,MMU接收CPU發出的虛擬地址,將其翻譯爲物理地址後發送給內存,內存按照該物理地址進行相應訪問後讀出或寫入相關數據。

2. 分頁內存

分頁系統的核心是將虛擬內存空間和物理內存空間皆劃分爲大小相同的頁面,如4KB、8KB或16KB等,並以頁面作爲內存空間的最小分配單位,一個程序的一個頁面可以存放在任意一個物理頁面裏。

只是簡單說說可能體現不出來分頁管理的優勢,讓我們思考下,除了分頁管理之外,簡單的內存管理該如何做呢?很容易想到的是分配和程序所需內存同樣大小的虛擬/物理內存,也就是基址極限管理,限定內存開始結束位置,隨着應用的執行,如果程序還需要更多空間,可以先swap到磁盤,再找一個大的連續空間然後再swap回內存,如果找不到就尷尬了,程序就stop the world了。這樣看起來也是一個方案,但是存在一個問題是,這樣分配內存的粒度太大,容易造成內存碎片,並且多個內存碎片加在一起可以滿足程序使用時也不能直接使用。

可能有的小夥伴會想,那就進行內存碎片整理,通過移動進程在內存裏面的位置將空閒空間連成一片。但是這種操作需要將進程swap到磁盤上,再重新加載,效率十分低下。在進行碎片整理的過程中,系統的響應延遲將顯著增加,這種方案不太可取。

2.1. 分頁管理

在分頁系統下,一個程序發出的虛擬地址由兩部分組成:頁面號和頁內偏移值。爲了解決程序比內存大的問題,我們可以允許一個進程的部分虛擬頁面存放在物理頁面之外,也就是磁盤上。在需要訪問這些外部虛擬頁面時,再將其調入物理內存,需要騰出空間時,將暫時不同的內存swap到磁盤。

分頁管理對於任一虛擬頁面,系統知道該頁面是否在物理內存中,如果在的話,其對應的物理頁面是哪個;如果不在的話,則產生一個系統中斷(缺頁中斷),並將該虛頁從磁盤轉到內存,然後將分配給它的物理頁面號返回,這個過程也就是前面說到的地址翻譯:

注意:地址翻譯只是針對頁面號的翻譯,即虛擬地址頁和物理地址頁的映射關係翻譯,因爲二者一一對應,頁內偏移量無需翻譯。

內存頁的翻譯是通過查表進行的,系統對於每個進程都爲其保存一個頁表,該頁表中存放的是虛擬頁面到物理頁面的映射。每當爲一個虛擬頁面尋找到一個物理頁面後,就在頁表裏面增加一個記錄來保留該虛擬頁面到物理頁面的映射關係,隨着虛擬頁面進出物理內存,頁表的內容頁不斷髮生變化。

進程發出一個虛擬地址給內存管理單元后,內存管理單元首先將地址裏面頁號部分的字位分離出來,然後判斷該虛擬頁面是否有效,是否存放在內存,是否受到保護。如果頁面無效,即該虛擬頁面不存在或沒有在內存,也就是說該虛擬頁面在物理內存裏面沒有對應。如果該頁面受到保護,即對該頁面的訪問被禁止,則產生一個系統中斷來處理這些特殊情況。對於無效頁面訪問,需要終止發出該無效訪問的進程。對於合法但不在物理內存中的頁面,我們通過缺頁中斷將該虛擬頁面放進物理內存。對於受保護的頁面,同樣終止該進程。判斷頁是否合法的信息也是存在頁面中的,如果頁面合法,則通過頁表找對對應物理頁號。

2.2. 頁表

頁表的根本功能是提供從虛擬頁面到物理頁面的映射,因此其地位十分關鍵,內存管理單元依賴頁表來進行一切與頁面有關的管理活動。這些活動包括判斷某一頁面號是否在內存裏,頁面是否受到保護,頁面是否非法空間等。由於頁表的特殊地位(使用非常頻繁),因此只能由硬件來實現,也即是說它是一個硬件數據結構。

對於32位尋址的虛擬地址,如果頁面大小爲4KB,則虛擬頁面數最多可以達到2的20次方,即1048576個虛擬頁面,那麼頁表的記錄條數就爲1048576條。這樣就佔用較多空間,如何減少頁表空間呢?這時可以使用多級頁,表頁表根據存放的內容可分爲:頂級頁表、一級頁表、二級頁表、三級頁表等。頂級頁表裏面存放的是一級頁表的信息,一級頁表裏面存放的是二級頁表的信息,以此類推,到最後一級頁表存放的纔是虛擬頁面到物理頁面的映射,就和MySQL中非聚集索引和聚集索引的關係類似。二級頁面結構如下:

2.3. 頁錶快速翻譯

地址翻譯因增加了內存訪問次數而降低了系統效率。如果只使用單級頁表,則每次內存訪問變爲兩次內存訪問,速度的下降還尚可以忍受。但如果使用多級頁表或反轉頁表,則每次內存訪問將變爲多於兩次的內存訪問,這樣效率的下降將非常明顯。我們都知道,程序的執行有時空侷限性,即在一段時間內,程序所要訪問的地址空間有一定的空間局域性。如果一個頁面被訪問,則該頁面的其他地址可能也將被隨後訪問。這樣,我們可以將該頁面的翻譯結果存放在緩存裏,而無須在訪問該頁面的每個地址時再翻譯一次。這樣就可以大大提高系統的執行效率。

這種存放翻譯結果的緩存稱爲翻譯快表(Translation Look-Aside Buffer,TLB)。TLB裏面存放的是從虛擬頁面到物理頁面的映射,其記錄的格式與內容和正常頁表的記錄格式與內容一樣:

TLB是線性表結構,那麼它的時間複雜度是多少呢?O(1),是不是不可思議?解決方案就是使用硬件,TLB的比較不是順序執行的,而是一次性比較其中所有數據,因此只需要一次查找就能確定一個虛擬頁面號是否在TLB裏。這種設計需要同時配備多套比較電路,比較電路的套數需與TLB的大小一樣。這也就是爲什麼TLB非常昂貴。

顯然,採用多級頁表的分頁系統的效率將取決於TLB的命中率。如果命中率很高,則系統效率高;如果命中率低,則系統效率低。例如,Linux使用的是三級頁表,按照常理來說,這將使得系統的執行效率大大降低,但許多人並沒有感覺到Linux特別慢,這就是因爲Linux的TLB命中率高,據稱其命中率達98%。

 推薦閱讀 


歡迎小夥伴關注【TopCoder】歡迎評論區留言討論交流。

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章