前言
? ? ? ? 本章主要講解虛擬地址是怎么轉化成物理地址的,以及頁表相關知識;本文環境默認為32位機器下;如果你連什么是虛擬地址都不知道可以先看看下面這篇文章;
Linux | 進程地址空間-CSDN博客
一、概念補充
頁表:是一種數據結構,與硬件MMU配合可以將虛擬地址轉化成物理地址,頁表中主要建立虛擬地址與物理地址之間的映射;
頁框:我們將真實物理內存以4KB為單位進行劃分,其中每一個4KB我們稱為一個頁框;
頁框號:識別頁框的編號;
知識回顧:?
????????之前我們講解磁盤文件時,我們說過,通常進行一次IO的大小通常為4KB,即使你只修改1字節也是以4KB為單位將數據先加載進內存中;實際上,也正是加載進內存的空閑頁框中;我們的磁盤文件也是以4KB進行劃分;
? ? ? ? 我們還說過我們的一個可執行程序在編譯后形成可執行程序,這個可執行程序實際上已經在內部進行分段,分好了虛擬地址空間了;我們可以直接使用編譯好的虛擬地址;
二、地址轉化過程
????????前面我們說過我們的物理內存會以4KB分為一個又一個頁框;而操作系統是否需要維護這些頁框呢?答案當然也是肯定的,我們可以將我們的頁框用一種結構體描述起來,然后用數組維護這些頁框,這樣就有一個頁框數組了,數組下標可作為頁框號;假設一個為4GB的物理內存,可以有多少個頁框呢?我們不難計算,4GB = 4 * 1024 * 1024 * 1024 Byte;
一個頁框為4KB = 4 * 1024;兩者相除,大約就是1024*1024,約一百萬個;我們便可以用
struct page[1000000]; 即可表示所有物理內存中所有頁框;
????????首先我要講解的是我們的虛擬地址通過頁表+MMU將我們的虛擬地址轉換成物理內存中的物理地址,若我們頁表中沒有物理內存中的地址,而是只有磁盤中的地址,此時是因為我們的數據沒有被加載進磁盤,可能之前發生或換出或本來沒有加載進磁盤內;這是我們在物理內存中申請一塊空閑的頁框,我們找到空閑的頁框后,我們將磁盤文件加載進指定的頁框,同時我們也在頁表上進行更新,將新映射的物理內存地址填上去;這個過程也就是我們常說的缺頁中斷;
? ? ? ? 如果按上面的結構來看,頁表中的每個條目記錄一個虛擬地址映射一個物理地址,此時我們一共則需要 4 * 1024 * 1024 * 1024條記錄(假設物理內存有4G);假設一條記錄需要10個字節,那么一個頁表的大小就需要40G;而我們的頁表也是存在物理內存中呀!這顯然是不可能存的下的,就算存的下也不可能消耗這么多內存資源存頁表,況且一個進程就有一張用戶級頁表;計算機中絕對不止有一個進程;
? ? ? ? 此時,我們用另一種思路,我們頁表中將虛擬地址的32個比特位分開看;其中前10位我們一起看,作為頁目錄的索引來找到二級頁表,然后接著10位用來查找頁框號,最后12個比特位用來記錄頁內偏移;如下圖所示;
? ? ? ? 我們來計算一下,頁目錄最多有2^10,也就是1024條目錄,對應著最多有1024個二級頁表;每個二級頁表也最有有2^10條目錄,每條目錄對應一個頁框號,所有二級頁表可以表示2^10 * 2^10 個頁框,而我們的4GB內存最多也只有 2^20 個頁框,剛好一一對應;最后12個比特位可以表示0到2^12 - 1,而2^12正好也就是4KB;也正好吻合;設頁表每一條目為10字節,計算最大的情況下,總大小為 頁目錄大小(2^10 * 10 = 10KB)+ 所有二級目錄大小(2 ^ 10 * 2 ^ 10 * 10 = 10MB);其中10KB可忽略,總大小最多為10M;這個大小比我們第一種方案要小了很多很多,這也是我們Linux下采用的方案;