您當前的位置:首頁 > 動漫

記憶體管理1:為什麼需要虛擬記憶體?

作者:由 Haonan 發表于 動漫時間:2021-08-29

目錄

1 先上結論

記憶體系統面臨哪些問題?

虛擬記憶體提供了哪些能力?

2 何為虛擬定址?

3 VM能力1:虛擬記憶體作為快取的工具

3。1 虛擬頁

3。2 頁表(PTE)

3。3 地址翻譯

3。4 頁命中

3。5 缺頁(指某個虛擬地址對應的物理地址沒有快取在記憶體中,只在磁盤裡)

3。6 使用TLB加速地址翻譯

3。7 多級頁表

4 VM能力2:虛擬記憶體作為記憶體管理的工具

5 VM能力3:虛擬記憶體作為記憶體保護的工具

6 linux虛擬記憶體系統

6。1 linux是如何組織虛擬記憶體的?

7 總結

參考文件

(文中圖片均來自《深入理解計算機系統(原書第三版)》,侵刪)

1 先上結論

為什麼需要虛擬記憶體?因為虛擬記憶體提供了三項能力,解決了物理記憶體系統面臨的兩個問題。

記憶體系統面臨哪些問題?

記憶體(memory)資源永遠都是稀缺的,當越來越多的程序需要越來越來記憶體時,某些程序會因為得不到記憶體而無法執行;

記憶體容易被破壞,一個程序可能誤踩其他程序的記憶體空間;

虛擬記憶體提供了哪些能力?

正如軟體工程中的其他抽象,

虛擬記憶體是作業系統物理記憶體和程序之間的中間層

。它為程序隱藏了物理記憶體這一概念,為程序提供了更加簡潔和易用的介面。這個中間層提供了三個重要的能力:

高效使用記憶體:VM將主存看成是儲存在磁碟上的地址空間的快取記憶體,主存中儲存熱的資料,根據需要在磁碟和主存之間傳送資料;

簡化記憶體管理:VM為每個程序提供了一致的地址空間,從而簡化了連結、載入、記憶體共享等過程;

記憶體保護:保護每個程序的地址空間不被其他程序破壞。 下文詳述這虛擬記憶體三項能力。

2 何為虛擬定址?

記憶體管理1:為什麼需要虛擬記憶體?

虛擬定址架構圖

CPU透過發出虛擬地址(Virtual Address, VA)來訪問主存,在被送達主存前透過記憶體管理單元(Memory Management Unit, MMU)翻譯成物理地址,最後主存將讀取到的資料傳遞給CPU。其中,

MMU利用存放在主存中的查詢表(即頁表,Page Table)來動態翻譯虛擬地址,該表的內容由作業系統管理

3 VM能力1:虛擬記憶體作為快取的工具

要想說清楚該能力,需要涉及以下7個方面的內容。

3.1 虛擬頁

VM系統透過將虛擬記憶體分割為虛擬頁(Virtual Page,VP)的大小固定的塊來作為磁碟和主存之間的傳輸單元;類似地,物理記憶體被分割為物理頁(Physical Page,PP),物理頁也被稱為頁幀(page frame)。

記憶體管理1:為什麼需要虛擬記憶體?

物理頁快取在DRAM中

虛擬頁(PP)有且僅有三個狀態:

未分配的:

VM系統還未分配(或建立 )的頁,未分配的塊沒有任何資料和它們相關聯,因此也就不佔用任何磁碟空間

快取的:當前已快取在物理記憶體中的已分配頁;

未快取的:未快取在物理記憶體中已分配頁,在磁碟上有對應的頁。

3.2 頁表(PTE)

虛擬記憶體系統需要有辦法判斷虛擬頁是否快取在DRAM的某個地方:如果命中,需要能找到虛擬頁對應的物理頁;如果不命中,需要能找到虛擬頁存放在磁碟哪個位置。這些內容是透過頁表實現的。

記憶體管理1:為什麼需要虛擬記憶體?

頁表架構圖

虛擬地址空間中的每個頁在一個固定偏移量處都有一個PTE(實際實現中,透過虛擬地址的多級頁表,層層索引到PTE)。

每個PTE的組成: 一個有效位(valid bit)和 一個n位地址欄位。

如果設定了有效位,地址欄位表示記憶體中相應物理頁的起始位置;

如果沒有設定有效位,空地址表示該虛擬頁未分配(未被分配的);

如果沒有設定有效位,非空的地址欄位指向虛擬頁在磁碟上的起始位置(未被快取的)。

3.3 地址翻譯

記憶體管理1:為什麼需要虛擬記憶體?

使用頁表的地址翻譯

地址翻譯的過程就是透過虛擬地址查詢物理地址的過程。CPU中存在一個控制暫存器,叫做頁表基址暫存器(X86中稱為Page Table Base Register,PTBR; ARM中稱為Translation Table Base Register,TTBR,另外TTBR0存放使用者空間一級頁表基址,TTBR1存放核心空間一級頁表基址)指向當前頁表。虛擬地址中的虛擬頁號VPN即為相對TTBR的偏移,此時則能在頁表中定位到一個條目,如果該條目的有效位為1,那該條目的地址欄位為物理頁號(PPN),最後組合上虛擬頁偏移量VPO,即為物理地址。

3.4 頁命中

記憶體管理1:為什麼需要虛擬記憶體?

頁命中過程示意

頁命中的五步走:

CPU發生訪存需求,發出虛擬地址到MMU;

MMU根據多級頁表,生成PTE地址(PTEA),向記憶體發出請求希望獲得PTE;

記憶體向MMU返回PTE;

PTE中有效位為1,MMU將PTE中的PPN拿出來,構造物理地址(透過物理頁號PPN + 虛擬地址中的頁偏移量VPO),並把它傳給主存;

主存返回所請求的資料給CPU。

3.5 缺頁(指某個虛擬地址對應的物理地址沒有快取在記憶體中,只在磁盤裡)

當有效位為0時,觸發缺頁異常,缺頁異常流程會替換記憶體中一個犧牲頁(如果該頁被修改過,即髒頁,會被寫回到硬碟),並更新頁表索引。然後返回重新執行導致缺頁的命令,該命令會重新把導致缺頁的虛擬地址傳送到MMU,這時就能命中了。

頁面命中完全是由硬體來處理的,而缺頁要求硬體和作業系統核心協作完成。

記憶體管理1:為什麼需要虛擬記憶體?

缺頁過程示意

缺頁的七步走:

1到3步與頁命中步驟相同;

PTE中有效位為0,MMU觸發一次異常,將PC指標轉移到OS中的缺頁異常處理程式;

缺頁異常處理程式明確物理記憶體中需要犧牲的頁面,如果該頁面是髒頁,將其換出到磁碟;

缺頁異常處理程式調入新的頁面,並更新記憶體中的PTE;

缺頁異常處理程式返回原來的程序,再次執行導致缺頁的指令。此時重新走頁面命中的流程。

3.6 使用TLB加速地址翻譯

每次CPU訪問一個虛擬記憶體,MMU都需要做一次訪存操作查詢PTE。為了提高效率,我們再引入一個快取——-TLB,它是頁表的快取,包含在MMU硬體中。

記憶體管理1:為什麼需要虛擬記憶體?

TLB架構圖

TLB命中就不多說了;TLB不命中時,MMU還是要去記憶體中取PTE,但是返回的PTE首先重新整理TLB,然後再在MMU中做地址翻譯。

3.7 多級頁表

以32位地址空間、4KB頁大小、一個PTE4位元組來算,即使應用程式只使用虛擬地址空間的一部分地址,

那也需要4MB的頁表駐留在記憶體中

。一個應用就佔4MB,應用多起來豈不爆炸,因此有了多級頁表。

記憶體管理1:為什麼需要虛擬記憶體?

使用多級頁表的地址翻譯

TTBR中存著一級頁表的基地址,VPN1是一級頁表的偏移,這樣就定位到了2級頁表的基地址,然後再根據偏移VPN2定位到3級頁表的基地址,以此類推最終找到PPN,再結合VPO形成物理地址。 這裡有兩點需要強調:

只有一級頁表才需要總是在主存中;虛擬記憶體系統可以在需要時建立、頁面調入或調出二級頁表,這就減少了主存的壓力;只有最經常使用的二級頁表才需要快取在主存中。 訪問k個PTE,第一眼看上去昂貴而不切實際。然後,這裡TLB能夠起作用,正是透過將不同層次上頁表的PTE快取起來。實際上,帶多級頁表的地址翻譯並不比單級頁錶慢很多。

4 VM能力2:虛擬記憶體作為記憶體管理的工具

作業系統為每個程序提供了獨立的頁表,也就意味著提供了獨立的虛擬地址空間。

記憶體管理1:為什麼需要虛擬記憶體?

每個程序有自己獨立的頁表

VM簡化了連結、載入、程式碼和資料共享以及應用程式的記憶體分配。

簡化連結:對每個應用程式來說,程式碼段、資料段、堆、棧的安排都是一致的,這樣的一致性極大的簡化了連結器的設計與實現。允許連結器生成完全連結的可執行檔案,這些可執行檔案是獨立於物理記憶體中程式碼和資料的最終位置的。

簡化載入:虛擬記憶體還使得容易向記憶體中載入可執行檔案和共享物件檔案。在把目標檔案的。text和。data載入到一個新建立的程序中時,linux載入器會為程式碼段和資料段分配虛擬頁。**同時把他們標識為無效的(即未被快取的),將頁表條目指向目標檔案中適當的位置(這個操作是為了在發生缺頁時,將目標檔案在磁碟中相應位置的內容緩衝到記憶體中)。**可以看到,載入器並不會從硬碟向記憶體複製任何資料,在每個頁初次被引用時,虛擬記憶體系統會透過缺頁處理程式自動將相應頁載入到記憶體中。

簡化共享:拿linux核心程式碼和C標準庫來說,每個程序都會用到,為了省物理記憶體,這個需求需要所有程序共享實現。OS會將不同程序中適當的虛擬頁面對映到相同的物理頁面,從而安排多個程序共享這部分程式碼的一個副本(只佔用了一份物理記憶體空間),而不是在每個程序中都包括單獨的核心和C標準庫的副本。

簡化記憶體分配:在使用malloc等記憶體分配函式時,由於頁表的存在,作業系統沒必要分配連續的物理頁面給程序,而是在程序自己的虛擬地址空間找一塊連續的虛擬地址分配給程序,當實際訪問這塊新分配的虛擬地址時,缺頁相關程式碼會將其對映到實際的物理記憶體中。

5 VM能力3:虛擬記憶體作為記憶體保護的工具

一個程序不能修改它的只讀程式碼段、核心的程式碼段和資料段、其他程序的私有記憶體等,這需要一定的保護機制。虛擬記憶體系統為每個程序實現的獨立地址空間為這種保護機制提供了自然的實現方式。

記憶體管理1:為什麼需要虛擬記憶體?

用虛擬記憶體實現記憶體保護

透過在PTE中新增標誌位,可以限制是否必須超級使用者(SUP)才能訪問,是夠可讀、可寫。 如果一條指令違反了這些條件,CPU會觸發一個保護故障,將PC傳遞給一個核心中的異常處理程式,這經常是所謂的“段錯誤(segmentation fault)”。

6 linux虛擬記憶體系統

記憶體管理1:為什麼需要虛擬記憶體?

一個linux程序的虛擬頁表

linux為每個程序維護了一個虛擬地址空間,

核心虛擬記憶體包含核心中的程式碼和資料結構,其中所有程序共享核心的程式碼和全域性資料結構

,另外,核心虛擬記憶體中也有每個程序都不相同的,包括頁表、核心在程序的上下文中執行程式碼時使用的棧,以及記錄虛擬地址空間當前組織的各種資料結構。

6.1 linux是如何組織虛擬記憶體的?

記憶體管理1:為什麼需要虛擬記憶體?

linux如何組織虛擬記憶體

一個程序對應一個task_struct結構體,其中的mm成員描述該程序虛擬記憶體的狀態,mm中pgd和mmap是兩個比較重要的成員。

pgd:指向第一級頁表(頁全域性目錄)的基址,running程序切換到該程序時,TTRB暫存器的值會被pgd成員覆蓋,用於尋找PTE。

mmap:mmap是一個虛擬記憶體區域的連結串列,這裡都是該程序已經申請的虛擬記憶體區域。

理解了mmap,可以再聊一下缺頁處理的過程。

記憶體管理1:為什麼需要虛擬記憶體?

MMU當試圖翻譯某虛擬地址A時,如果相應PTE的有效位為0時,會觸發缺頁。此時會有以下步驟:

判斷虛擬地址A是否為不存在的頁面:遍歷vm_area,如果該虛擬地址不在任何vm_area中,則報段錯誤;

判斷虛擬地址A是否有相應的讀寫許可權:遍歷vm_area,確認讀寫操作與相應頁面的許可權是一致的;

如果不是以上的情況,那麼就選擇犧牲頁,向記憶體中換入新的頁面,並更新頁表。

7 總結

回到我們最初的問題,為什麼需要虛擬記憶體? 因為計算機記憶體系統面臨兩個棘手的問題:記憶體短缺 + 記憶體訪問需要做保護。而虛擬記憶體系統提供的三個重要功能,可以有效解決這兩個問題。 (1)虛擬記憶體系統在記憶體中自動快取最近使用的存放在磁碟上的虛擬地址空間的內容(透過缺頁實現); (2)虛擬記憶體系統簡化了記憶體管理,進而又簡化了連結、程序間共享資料、程序的記憶體分配和程式載入。 (3)虛擬記憶體系統透過在頁表條目中加入保護位,從而簡化了記憶體保護。

參考文件

https://

draveness。me/whys-the-d

esign-os-virtual-memory/

《深入理解計算機系統(原書第三版)》

歡迎在評論區和我討論,在交流中一起進步。