基於《CSAPP第九章 虛擬內存》的思考和總結

  • 2021 年 12 月 7 日
  • 筆記

在csapp的描述中,虛擬內存的形象更加具化,虛擬內存被組織為一個由存放在磁盤上的N個連續的位元組大小的單元組成的數組,內存充當了磁盤的緩存,粗呢內存的許多概念與SRAM緩存是相似的。虛擬頁面有以下三種狀態:

  1. 未分配(pte的有效位為0,且pte的地址段為空)
  2. 未緩存(pte的有效位為0,且pte的地址段指向磁盤的某一位置)
  3. 已緩存(pte的有效位為1,且pte的地址段指向內存的某一位置)

這是將物理地址的範圍擴大到除了內存之外,還包含磁盤。虛擬地址照常根據MMU進行多級頁錶轉換,得到的地址可能是物理頁號(內存中)或者磁盤地址。虛擬內存系統是虛擬地址的擴展應用。

在xv6系統和JOS系統中,並沒有使用到磁盤上的虛擬內存,MMU得到的結果始終在內存上,否則就是缺頁,在內存上分配新的頁面,並無磁盤的利用。推測應該使用swap交換區來實現。

當操作系統調用malloc分配一個新的虛擬內存頁的時候,首先會在磁盤上創建空間,並更新PTE。

在磁盤和內存之間傳送頁面的活動稱為交換(swapping)或者頁面調度,分為換入和換出。頁面調度通常發生在有不命中發生的時候,這叫做按需頁面調度。也可以通過預測的方式提前將可能用到的頁面調入內存,這就有點像分支預測,但通常不被使用,可能是因為比起分支預測的懲罰,頁面調度失敗的代價比較大。由於程序的局部性,頁面調度可能不需要頻繁發生,如果工作集的大小超過了物理內存的大小,就不可避免地會發生頻繁的換入換出,這種狀態稱為抖動,會大大影響程序的性能。不管虛擬地址翻譯的結果在不在磁盤,最終cpu都要從內存讀數據,因此如果不在內存,有效位會是0,發生正常的缺頁,進行頁面調度,如果內存已滿,則要根據一些策略選擇換出頁面,這裡還涉及到像緩存里相似的直寫和寫回的選擇

【缺頁異常可能有三種原因】

  1. 段錯誤,訪問一個不存在的頁面;
  2. 正常缺頁,則進行頁面調度,然後重新執行;
  3. 保護異常,違反了頁面的權限許可,返回錯誤碼即可。

此外,pte上不止有有效位,還有各種標誌位,控制了不同程序對頁面的訪問和讀寫權限。正因為此,我們說虛擬內存可以更好地管理內存。

【關於共享內存
比如圖中的PP6,操作系統對共享內存的控制是:不允許進程修改任何與其他進程共享的虛擬頁面,除非所有的共享者都顯式地允許它這麼做。
在Copy-On-Write中,當需要寫一段共享內存的時候,會將這段內存在另一個內存區域複製出副本,此時便不再是共享的內存,不必受到共享內存的限制。在其它情況下,如果要寫共享內存,則需要對共享者之間的進程通信,得到所有進程的允許信號後才寫入。
【由共享內存,可以擴展到C++多線程編程中的共享對象】
進程與線程的區別是,不同進程有不同的頁表基地址,不容易出現共享內存,而線程作為一個進程內的子單元,使用同樣的頁表基地址,內存都是共享的。(在xv6實驗multithreading中,提到linux對多線程的支持,待總結。)當一個對象被多個線程同時使用的時候,常常採用加鎖的方式、或者shared_ptr/weak_ptr這種智能指針的方式保證數據讀寫安全,尤其是對象析構時期的安全,此時,這段共享內存的安全讀寫需要另一段內存里的對象的鎖成員,或者棧上的智能指針來保護,這些都是在用戶進程中顯式約定的,而不是由OS控制。

【虛擬地址到物理地址的翻譯過程】

虛擬內存的映射和高速緩存比較相似,那麼虛擬內存和高速緩存是怎麼結合,共同為CPU提供數據服務的呢?
答案是,CPU查找數據的時候,首先去cache中查找,cache查找失敗的話,也是先從內存load到cache中,總之是一定經過cache的,這樣的緩存原理也可以解釋為什麼近期瀏覽的網頁記錄丟失的話,可以從緩存里找到蹤跡,因為近期訪問過的內存都會存入緩存。

除了cache高速緩存之外,為了讓cpu更快地訪問內存,還有第二個措施,就是TLB快表。cache緩存的是物理地址對應的數據,快表緩存的是虛擬地址對應的物理地址,存放於MMU中,與處理器同在CPU芯片內。