MMU
?摘自維基百科:
內存管理單元(英語:memory management unit,縮寫爲MMU),有時稱做分頁內存管理單元(英語:paged memory management unit,縮寫爲PMMU)。它是一種負責處理中央處理器(CPU)的內存訪問請求的計算機硬件。它的功能包括虛擬地址到物理地址的轉換(即虛擬內存管理)[1]、內存保護、中央處理器高速緩存的控制,在較爲簡單的計算機體系結構中,負責總線的仲裁以及存儲體切換(bank switching,尤爲是在8位的系統上)。
在開始以前,但願讀者簡略讀過我以前寫的一篇文章:web
如下論述,皆以32位爲例
對於一個有MMU的CPU而言,MMU開啓後,CPU是這樣尋址的:CPU任什麼時候候,一切時候,發出的地址都是虛擬地址
,這個虛擬地址發給MMU後,MMU經過頁表來在頁表裏面查出來這個虛擬地址對應的物理地址是什麼,從而去訪問外面的內存條。MMU裏面的頁表地址寄存器,記錄了頁表自己的存放位置。
分頁存儲管理將一個進程的邏輯地址空間(就是虛擬地址空間)分紅若干個大小相等的片,稱爲頁面或頁,相應地,把內存空間分紅與頁面相同大小的若干個存儲塊,稱爲(物理)塊或者頁框svg
如今咱們假設每一頁的大小是4KB(意思就是將虛擬地址空間和物理地址空間均分爲小塊(4KB)),以下所示:
並且假設頁表只有一級,這個頁表長成下面這個樣子,頁表的每一行是32個bit
當CPU訪問虛擬地址0的時候,MMU會去查上面頁表的第0行,發現第0行沒有命中,因而不管以何種形式(R讀,W寫,X執行)訪問,MMU都會給CPU發出page fault
,CPU自動跳到fault的代碼去處理fault
。操作系統
當CPU
訪問虛擬地址4KB
的時候,MMU
會去查上面頁表的第1行(4KB/4KB=1),發現第1行命中,(爲何是第一行,在我上一篇文章中有講到.不過我下面也會提到,先不用着急)若是這個時候.net
用戶是執行讀或者執行,則MMU
去訪問內存條的6MB
這個地址,由於頁表裏面記錄該頁的權限是RX
;3d
用戶是去寫4KB,因爲頁表裏面第1行記錄的權限是RX,沒有記錄你有寫的權限,MMU會給CPU發出page fault,CPU自動跳到fault的代碼去處理fault。code
當CPU訪問虛擬地址8KB+16的時候,MMU會去查上面頁表的第2行(8KB/4KB=2),發現第2行命中了物理地址8M,這個時候,MMU會訪問內存條的8MB+16這個物理地址。固然,權限檢查也是須要的。
…
當CPU訪問虛擬地址3GB的時候,MMU會去查上面頁表的第3GB/4KB行,表中記錄命中了,查到虛擬地址3GB對應的物理地址是0,因而MMU去訪問內存條上的地址0。可是,這個訪問分紅2種狀況:xml
CPU在執行用戶態程序的時候,去訪問3GB,因爲頁表裏面記錄的U+K權限只有K,因此U是沒權限的,MMU會給CPU發出page fault,CPU自動跳到fault的代碼去處理fault;blog
CPU在執行內核態程序的時候,去訪問3GB,因爲頁表裏面記錄的U+K權限只有K,因此K是有權限的,MMU不會給CPU發出page fault,程序正常執行。索引
那麼頁表到底是多大吶?
若是頁表只有1級,每4KB的虛擬地址空間就須要頁表裏面的一行(32bit),那麼CPU要覆蓋到整個4GB的虛擬內存,就須要這個頁表的大小是:
4GB/4KB *4 = 4MB
任何一個虛擬地址都是下面的這個樣子:
如今咱們假設在Linux裏面有2個進程,一個是QQ,一個是Firefox,他們的頁表分別以下:
當CPU在執行QQ的時候,Linux會把QQ的頁表的物理地址255MB,填入MMU的頁表地址寄存器,因而這個時候,QQ的頁表生效。根據頁表內容,CPU若是訪問4KB這個虛擬地址的話,MMU訪問內存條的6MB物理地址;CPU若是訪問8KB這個虛擬地址的話,MMU訪問內存條的8MB物理地址;CPU若是訪問3GB這個虛擬地址的話,MMU訪問內存條的0MB物理地址;
當CPU在執行Firefox的時候,Linux會把Firefox的頁表的物理地址280MB,填入MMU的頁表地址寄存器,因而這個時候,Firefox的頁表生效,QQ的頁表淡出江湖。根據頁表內容,CPU若是訪問4KB這個虛擬地址的話,MMU訪問內存條的100MB物理地址;CPU若是訪問8KB這個虛擬地址的話,MMU訪問內存條的200MB物理地址;CPU若是訪問3GB這個虛擬地址的話,MMU訪問內存條的0MB物理地址。
上面咱們發現一個共同點,QQ和Firefox去訪問3GB虛擬地址的時候,最終MMU訪問的都是0MB這個物理地址,具體緣由很是簡單,QQ和Firefox,這2張頁表裏面,3GB/4KB這一行,裏面填的是徹底同樣的東東。
爲何3GB的虛擬地址對應的物理地址是是0?
在Linux下爲0的低端內存都會直接往3GB線性映射.其他系統看硬件
上面咱們發現,若是採用一級頁表的話,每一個進程都須要1個4MB的頁表,這個空間浪費仍是很大,並且要求連續,這顯然是不現實的.因而咱們能夠採用二級或者三級頁表。舉例以下,假設咱們用地址的高10位做爲一級頁表的索引,中間10位做爲2級頁表的索引。CPU訪問虛擬地址16,這個地址若是分解爲10/10/12位的話,就是這個樣子:
那麼MMU會用0這個下標去訪問一級頁表(一級頁表的地址填入MMU的頁表地址寄存器)的第0行,第0行的內容寫的是2MB(此處再也不是最終的物理地址,而是二級頁表的物理地址),證實二級頁表的地址在2MB,因而MMU自動去以中間的10位做爲下標,去查詢位置在2MB的二級頁表,在2級頁表裏面,最終查到第0頁(地址範圍0x00000000~0x00000FFF)這個虛擬地址的物理地址是1GB(這是本身定義的,沒有來源),因而MMU去訪問內存條的1GB+16這個物理地址。
據以上分析,1級頁表佔據的內存是2的10次方,再乘以4,即4KB。而每一個二級頁表,也是2的10次方,再乘以4,即4KB。分級機制的主要好處是,二級頁表不是必定存在了,好比一級頁表的第2行不命中,也即以下地址都無效的話:
那麼這一行對應的二級頁表,就整個都不須要了,因而就省掉了這段區間4KB二級頁表的內存佔用
。頁表固然還有是三級甚至更多(LInux中採用三級頁表)。
至於有多級頁表的時候,其實MMU也只須要知道一級頁表的基地址便可。
每次切換進程的時候,把一級頁表的地址從新填入MMU,把新的進程的各個頁表激活便可。
轉載自:Linux閱碼場