首先,我們得理清分頁的概念;
在計算中,存儲的最小的單位是位(bit),其值要么是0,要么是1。而單純的0或1所能表示的信息極為有限,所以,在計算機(jī)中,我們以最小一個字節(jié)(Byte,字)為基本單位來進(jìn)行操作,存儲我們的數(shù)據(jù)。(注釋:對于布爾類型,值為1或0,理論上只占一位,但在計算機(jī)中,實(shí)際操作時一般是占用一個字節(jié)的空間,當(dāng)然,在具體實(shí)現(xiàn)中也可能多于一個字節(jié)。)
操作系統(tǒng)對每一個字節(jié)進(jìn)行了編號,比如從0000 0000開始,然后是0000 0001,再然后是0000 0002,0000 0003 、、、

根據(jù)不同的系統(tǒng),不同的內(nèi)存大小,所用來進(jìn)行地址計數(shù)的數(shù)的位數(shù)有所差別,但道理不變;
然后,為了解決在操作中面臨的一些問題,我們想出了分頁的辦法,什么是分頁呢?就是原本是以一個字節(jié)為最小單位去存取數(shù)據(jù),這樣地址實(shí)在是太多了,每次一個一個的去找,實(shí)在是很麻煩,而且,我們經(jīng)常會使用一段連續(xù)的空間。
有沒有什么辦法可以不這么麻煩呢 ?有的,就是分頁。
我們將連續(xù)的一定數(shù)量的字節(jié)(通常一頁大小為1KB~8KB)視為一個整體(邏輯上),即為一頁,然后對頁進(jìn)行編號,比如從0000 0000開始,然后是0000 0001,再然后是0000 0002,0000 0003 、、、
舉例:計算機(jī)內(nèi)存物理地址編碼為0000 0000 0000 0000 ~ 1111 1111?1111 1111,(計算機(jī)內(nèi)存地址以二進(jìn)制來計數(shù),我們在C語言中看到的16位地址,實(shí)際上是邏輯地址,是面向用戶的,并非實(shí)際進(jìn)行操作時的最底層物理地址)
如果我們把連續(xù)的2KB( Byte)視為一頁,那么內(nèi)存可以被分為
?÷?
?= ?
塊(在邏輯地址中,我們稱為頁,在實(shí)際物理地址中,稱為塊。本質(zhì)是操作系統(tǒng)同時和用戶程序和實(shí)際物理地址打交道,對于用戶程序,我們約定為頁;對于實(shí)際物理地址,操作系統(tǒng)將同樣大小的內(nèi)存空間視為塊),然后操作系統(tǒng)對塊進(jìn)行編號,從 0000 0 到 1111 1;(這是操作系統(tǒng)和我們的約定,最底層的物理內(nèi)存可不知道我們把它們看成了一塊一塊的)

然后,我們需要使用內(nèi)存的時候,就去和操作系統(tǒng)打交道,告訴它我們需要多少內(nèi)存,然后操作系統(tǒng)根據(jù)內(nèi)存使用情況,判別還有哪些塊是空的,然后分配給我們需要的大小的塊數(shù),分頁的優(yōu)點(diǎn)在這個步驟就體現(xiàn)出來了,可以不用一定分配連續(xù)的內(nèi)存空間給用戶程序,而是分配?頁?給用戶程序,可以是不連續(xù)的??墒?,頁可以是不連續(xù)的,那我們怎么知道我們被分到了哪些頁呢?嗯,所以操作系統(tǒng)在分配內(nèi)存時要建立一個表,表中記錄你是哪個程序,分配給了你哪些頁。
在用戶程序的運(yùn)行過程中,各種操作都是給出邏輯上的操作,然后,交給操作系統(tǒng)去實(shí)現(xiàn)。
比如:
我們在上面的假設(shè)的基礎(chǔ)上,現(xiàn)在一個程序向操作系統(tǒng)申請10KB(即5頁)的空間,操作系統(tǒng)就會根據(jù)目前的內(nèi)存使用情況,進(jìn)行分配。假設(shè)內(nèi)存現(xiàn)在夠用, 操作系統(tǒng)分給程序5頁的內(nèi)存空間的使用權(quán)限,程序就會知道自己有5頁的內(nèi)存空間可用,編號為 0 - 4,即 000 ~ 100。但是,這5頁在程序看來是連續(xù)的,在操作系統(tǒng)這里,其實(shí)不一定是連續(xù)的,可能是下圖的情況:

如果用戶程序想訪問邏輯地址為?0001 1101 1011 1010 的內(nèi)存,需要由操作系統(tǒng)進(jìn)行轉(zhuǎn)換,操作系統(tǒng)得到實(shí)際的物理地址后,告訴用戶程序,諾,這就是你要訪問的內(nèi)存,然后程序在上面操作,下面講解具體的過程。
當(dāng)用戶提出內(nèi)存訪問請求時,分頁地址變換機(jī)構(gòu)會將所提交訪問的邏輯地址轉(zhuǎn)換為實(shí)際物理地址:
首先,將邏輯地址拆分為兩部分,頁號 + 頁內(nèi)地址 ?比如:
邏輯地址為0001 1101 1011 1010?的內(nèi)存地址,根據(jù)前面的條件,頁號是 5 位,即:
頁號: 0001 1 ?+ ?頁內(nèi)偏移: 101 1011 1010
然后去找到頁表,去其中找到與頁號對于的物理塊,在找之前,要根據(jù)頁號,判斷一波,看頁號是不是越界了,比如,在這里頁號是 0001 1 =》 3 ,沒有超過操作系統(tǒng)分配給程序的頁的上限5,所以沒有越界,如果越界了,操作系統(tǒng)會產(chǎn)生越界中斷。
在這里,有個問題需要解決,頁表在哪里呢?在上面我們知道那個對應(yīng)關(guān)系(頁=》塊)是由操作系統(tǒng)維持的,操作系統(tǒng)把它放在哪里的呢?
由于邏輯地址到物理地址的轉(zhuǎn)換是很頻繁的操作,所以考慮用寄存器來存放頁表,這樣可以大大提高速度,但通常頁表很大,如果全部放在寄存器里,那成本就太高了,所以,退一步,我們把頁表存放在內(nèi)存里。這里需要回顧一下,內(nèi)存是由一個個字節(jié)遞增的地址表示的,我們前面討論的都是內(nèi)存的管理與分配問題。我們前面的問題都還沒有解決,那我們把頁表放在內(nèi)存里,怎么放呢?它需要用到頁表嗎?那不成了它依賴自己的死循環(huán)了?嗯,實(shí)際是存放頁表時不需要依賴頁表,操作系統(tǒng)把頁表存在內(nèi)存中一段連續(xù)的空間,然后有個起始地址(這個是真實(shí)的物理地址),還有個頁表長度(即頁表有多大,占用了多少空間),然后,操作系統(tǒng)把這兩個信息放到一個寄存器里。
操作系統(tǒng)需要用到頁表的時候,就去寄存器處取得頁表相關(guān)信息(首地址+頁表大小)。
那我們是怎樣去從頁表獲得物理塊的呢?
首先,將頁表在內(nèi)存中的開始地址作為起始地址(圖中紅色線的地址):

加上表項(xiàng)的增量,(即 ?頁號 ?× ?每個表項(xiàng)所占的內(nèi)存大?。?,便來到了存放有該頁號在頁表中對應(yīng)的表項(xiàng)的位置(圖中綠色線的位置)。取出其中的內(nèi)容(頁號+對應(yīng)的塊號),便可獲得實(shí)際的物理塊號;僅僅得到物理塊是不夠的,還得知道在物理塊中的什么位置,因?yàn)榫唧w操作的時候,操作系統(tǒng)還是以字節(jié)為基本單位進(jìn)行操作的。回到所請求的地址(邏輯地址),我們利用了前面一部分,還有后面一部分?,F(xiàn)在我們來將它利用起來,把它直接作為物理地址的后一部分就可以了。獲得了實(shí)際的物理塊,我們加上頁內(nèi)偏移(邏輯地址的后一部分),即可獲得物理地址,所以物理地址是:
3 + 101 1011 1010 ?=》 ?1011 0 + 101 1011 1010 ?=》?1011 0101 1011 1010
于是,一個用戶程序邏輯地址就被操作系統(tǒng)轉(zhuǎn)換為了實(shí)際物理地址。
總結(jié):