(C語言內存八)MMU部件以及對內存權限的控制


引言

通過頁表完成虛擬地址和物理地址的映射時,要經過多次轉換,還要進行計算,如果由操作系統來完成這項工作,那將會成倍降低程序的性能,得不償失,所以這種方式是不現實的。

MMU

在CPU內部,有一個部件叫做MMU(Memory Management Unit,內存管理單元),由它來負責將虛擬地址映射為物理地址,如下圖所示:

在頁映射模式下,CPU 發出的是虛擬地址,也就是我們在程序中看到的地址,這個地址會先交給 MMU,經過 MMU 轉換以后才能變成了物理地址。

MMU緩存

即便是這樣,MMU也要訪問好幾次內存,性能依然堪憂,所以在MMU內部又增加了一個緩存,專門用來存儲頁目錄和頁表。MMU內部的緩存有限,當頁表過大時,也只能將部分常用頁表加載到緩存,但這已經足夠了,因為經過算法的巧妙設計,可以將緩存的命中率提高到 90%,剩下的10%的情況無法命中,再去物理內存中加載頁表。

有了硬件的直接支持,使用虛擬地址和使用物理地址相比,損失的性能已經很小,在可接受的范圍內。

MMU 只是通過頁表來完成虛擬地址到物理地址的映射,但不會構建頁表,構建頁表是操作系統的任務。在程序加載到內存以及程序運行過程中,操作系統會不斷更新程序對應的頁表,並將頁目錄的物理地址保存到 CR3 寄存器。MMU 向緩存中加載頁表時,會根據 CR3 寄存器找到頁目錄,再找到頁表,最終通過軟件和硬件的結合來完成內存映射。
CR3 是CPU內部的一個寄存器,專門用來保存頁目錄的物理地址。
每個程序在運行時都有自己的一套頁表,切換程序時,只要改變 CR3 寄存器的值就能夠切換到對應的頁表。

對內存權限的控制

MMU 除了能夠完成虛擬地址到物理地址的映射,還能夠對內存權限進行控制。上節《分頁機制究竟是如何實現的?》講到,在頁表數組中,每個元素占用4個字節,也即32位,我們使用高20位來表示物理頁編號,還剩下低12位,這12位就用來對內存進行控制,例如,是映射到物理內存還是映射到磁盤,程序有沒有訪問權限,當前頁面有沒有執行權限等。

程序控制地址

操作系統在構建頁表時將內存權限定義好,當MMU對虛擬地址進行映射時,首先檢查低12位,看當前程序是否有權限使用,如果有,就完成映射,如果沒有,就產生一個異常,並交給操作系統處理。操作系統在處理這種內存錯誤時一般比較粗暴,會直接終止程序的執行。

請看下面的代碼:

#include <stdio.h>
int main() {
    char *str = (char*)0XFFF00000;  //使用數值表示一個明確的地址
    printf("%s\n", str);
    return 0;
}

這段代碼不會產生編譯和鏈接錯誤,但在運行程序時,為了輸出字符串,printf() 需要訪問虛擬地址為 0XFFFF00000 的內存,但是該虛擬地址是被操作系統占用的(下節會講解),程序沒有權限訪問,會被強制關閉,如下圖所示:
image

而在Linux下,會產生段錯誤(Segment Fault),相信大家在編程過程中會經常見到這種經典的內存錯誤。


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM