記憶體定址之分頁機制/
分頁機制在段機制之後進行,以完成線性—實體地址的轉換過程。段機制把邏輯位址轉換為線性位址,分頁機制進一步把該線性位址再轉換為實體地址。
80386使用4k位元組大小的頁。每一頁都有4k位元組長,並在4k位元組的邊界上對齊,即每一頁的起始位址都能被4k整除。因此,80386把4g位元組的線性位址空間,劃分為1m個頁面,每頁有4k位元組大小。分頁機制通過把線性位址空間中的頁,重新定位到實體地址空間來進行管理,因為每個頁面的整個4k位元組作為乙個單位進行對映,並且每個頁面都對齊4k位元組的邊界,因此,線性位址的低12位經過分頁機制直接地作為實體地址的低12位使用。
假設每個程序都占用了4g的線性位址空間,頁表共含1m個表項,每個表項佔4個位元組,那麼每個程序的頁表要佔據4m的記憶體空間。為了節省頁表占用的空間,我們使用兩級頁表。每個程序都會被分配乙個頁目錄,但是只有被實際使用頁表才會被分配到記憶體裡面。一級頁表需要一次分配所有頁表空間,兩級頁表則可以在需要的時候再分配頁表空間。
兩級表結構的第一級稱為頁目錄,儲存在乙個4k位元組的頁面中。頁目錄表共有1k個表項,每個表項為4個位元組,並指向第二級表。線性位址的最高10位(即位31~位32)用來產生第一級的索引,由索引得到的表項中,指定並選擇了1k個二級表中的乙個表。
兩級表結構的第二級稱為頁表,也剛好儲存在乙個4k位元組的頁面中,包含1k個位元組的表項,每個表項包含乙個頁的物理基位址。第二級頁表由線性位址的中間10位(即位21~位12)進行索引,以獲得包含頁的實體地址的頁表項,這個實體地址的高20位與線性位址的低12位形成了最後的實體地址,也就是頁轉化過程輸出的實體地址。
兩級頁表結構
頁目錄項結構
頁面項結構
80386的每個頁目錄項指向乙個頁表,頁表最多含有1024個頁面項,每項4個位元組,包含頁面的起始位址和有關該頁面的資訊。頁面的起始位址也是4k的整數倍,所以頁面的低12位也留作它用。
第31~12位是20位物理頁面位址,除第6位外第0~5位及9~11位的用途和頁目錄項一樣,第6位是頁面項獨有的,當對涉及的頁面進行寫操作時,d位被置1。
4gb的記憶體只有乙個頁目錄,它最多有1024個頁目錄項,每個頁目錄項又含有1024個頁面項,因此,記憶體一共可以分成1024×1024=1m個頁面。由於每個頁面為4k個位元組,所以,儲存器的大小正好最多為4gb。
32位線性位址到實體地址的轉換
cr3包含著頁目錄的起始位址,用32位線性位址的最高10位a31~a22作為頁目錄的頁目錄項的索引,將它乘以4,與cr3中的頁目錄的起始位址相加,形成相應頁表的位址。
從指定的位址中取出32位頁目錄項,它的低12位為0,這32位是頁表的起始位址。用32位線性位址中的a21~a12位作為頁表中的頁面的索引,將它乘以4,與頁表的起始位址相加,形成32位頁面位址。
將a11~a0作為相對於頁面位址的偏移量,與32位頁面位址相加,形成32位實體地址。
從奔騰處理器開始,intel微處理器引進了擴充套件分頁,它允許頁的大小為4mb。
頁面快取記憶體
由於在分頁情況下,每次儲存器訪問都要訪問兩級頁表,這就大大降低了訪問速度。所以,為了提高速度,在386中設定乙個最近訪問頁面的快取記憶體硬體機制,它自動保持32項處理器最近使用的頁面位址,因此,可以覆蓋128k位元組的儲存器位址。當進行儲存器訪問時,先檢查要訪問的頁面是否在快取記憶體中,如果在,就不必經過兩級訪問了,如果不在,再進行兩級訪問。平均來說,頁面快取記憶體大約有98%的命中率,也就是說每次訪問儲存器時,只有2%的情況必須訪問兩級分頁機構。這就大大加快了速度。
linux使用了乙個適合32位和64位系統的分頁機制。
linux分頁模型
頁全域性目錄包含若干頁上級目錄的位址,頁上級目錄又依次包含若干頁中間目錄的位址,而頁中間目錄又包含若干頁表的位址。每乙個頁表項指向乙個頁框。線性位址因此被分成五個部分。圖中沒有顯示位數,因為每一部分的大小與具體的計算機體系結構有關。
對於沒有啟用實體地址擴充套件的32位系統,兩級頁表已經足夠了。從本質上說linux通過使「頁上級目錄」位和「頁中間目錄」位全為0,徹底取消了頁上級目錄和頁中間目錄字段。不過,頁上級目錄和頁中間目錄在指標序列中的位置被保留,以便同樣的**在32位系統和64位系統下都能使用。核心為頁上級目錄和頁中間目錄保留了乙個位置,這是通過把它們的頁目錄項數設定為1,並把這兩個目錄項對映到頁全域性目錄的乙個合適的目錄項而實現的。
啟用了實體地址擴充套件的32 位系統使用了**頁表。linux的頁全域性目錄對應80×86 的頁目錄指標表(pdpt),取消了頁上級目錄,頁中間目錄對應80×86的頁目錄,linux的頁表對應80×86的頁表。
最後,64位系統使用**還是四級分頁取決於硬體對線性位址的位的劃分。
這裡我們不討論**實現,只關注原理。從上面的討論可以看到分頁機制主要依賴硬體的實現。linux採用的四級頁表只是為了最大化相容不同的硬體實現,單就ia32架構的cpu來說,就有多種分頁實現,常規分頁機制,pae機制等。
我們雖然討論的是linux的分頁機制,實際上我們用了大部分篇幅來討論intel cpu的分頁機制實現。因為linux的分頁機制是建立在硬體基礎之上的,不同的平台需要有不同的實現。linux在軟體層面構造的虛擬位址,最終還是要通過mmu轉換為實體地址,也就是說,不管linux的分頁機制是怎樣實現的,cpu只按照它的分頁實現來解讀線性位址,所以linux傳給cpu的線性位址必然是滿足硬體實現的。例如說:linux在32位cpu上,它的四級頁表結構就會相容到硬體的兩級頁表結構。可見,linux在軟體層面上做了一層抽象,用四級頁表的方式相容32位和64位cpu記憶體定址的不同硬體實現。
最後分享兩篇linux記憶體定址的實驗文件,結合例項更容易理解。
linux記憶體位址對映
linux核心在x86_64 cpu中位址對映
參考資料
《深入理解linux核心》
《深入分析linux核心原始碼》
Linux記憶體定址之分段機制
最近在學習linux核心,讀到 深入理解linux核心 的記憶體定址一章。原本以為自己對分段分頁機制已經理解了,結果發現其實是一知半解。於是,查詢了很多資料,最終理順了記憶體定址的知識。現在把我的理解記錄下來,希望對核心學習者有一定幫助,也希望大家指出錯誤之處。相信學過作業系統課程的人都知道分段分頁...
Linux 記憶體定址之分段機制
最近在學習linux核心,讀到 深入理解linux核心 的記憶體定址一章。原本以為自己對分段分頁機制已經理解了,結果發現其實是一知半解。於是,查詢了很多資料,最終理順了記憶體定址的知識。現在把我的理解記錄下來,希望對核心學習者有一定幫助,也希望大家指出錯誤之處。相信學過作業系統課程的人都知道分段分頁...
Linux之分段機制和分頁機制
通用作業系統的設計原則 盡量縮短系統的平均響應時間並提高系統的吞吐率,在單位時間內為盡可能多的為使用者請求提供服務。如對於整個系統來說,注重所有任務的平均響應時間而不關心單個任務的響應時間,對於某個單個任務來說,注重每次執行的平均響應時間而不關心某次特定執行的響應時間。比如記憶體管理中的lru替換策...