Linux支持多種硬件體系結(jié)構(gòu),因此Linux必須采用通用的方法來描述內(nèi)存,以方便對內(nèi)存進(jìn)行管理。為此,Linux有了內(nèi)存節(jié)點(diǎn)、分區(qū)、頁框的概念。
內(nèi)存節(jié)點(diǎn):主要依據(jù)CPU訪問代價的不同而劃分。多CPU下環(huán)境下,本地內(nèi)存和遠(yuǎn)端內(nèi)存就是不同的節(jié)點(diǎn)。即使在單CPU環(huán)境下,訪問所有內(nèi)存的代價都是一樣的,Linux內(nèi)核依然存在內(nèi)存節(jié)點(diǎn)的概念,只不過只有一個內(nèi)存節(jié)點(diǎn)而已。內(nèi)核以struct pg_data_t來描述內(nèi)存節(jié)點(diǎn)。
內(nèi)存分區(qū)(ZONE):Linux對內(nèi)存節(jié)點(diǎn)再進(jìn)行劃分,分為不同的分區(qū)。內(nèi)核以struct zone來描述內(nèi)存分區(qū)。通常一個節(jié)點(diǎn)分為DMA、Normal和High Memory內(nèi)存區(qū)。
DMA內(nèi)存區(qū):即直接內(nèi)存訪問分區(qū),通常為物理內(nèi)存的起始16M。主要是供一些外設(shè)使用,外設(shè)和內(nèi)存直接訪問數(shù)據(jù)訪問,而無需系統(tǒng)CPU的參與。
Normal內(nèi)存區(qū):從16M到896M內(nèi)存區(qū)。
HighMemory內(nèi)存區(qū):896M以后的內(nèi)存區(qū)。
896M是個分界點(diǎn),低于這個界限的稱為low memory,高于這個界限的稱為high memory。low memory包含了ZONG_NORMAL+ZONE_DMA。
32位Linux虛擬內(nèi)存空間為0-4G,其中0-3G用于用戶態(tài),3G-4G用于內(nèi)核態(tài)。其中相當(dāng)于內(nèi)核態(tài)又分為3G-3G+896M 和3G+896M-4G 這兩個部分,其中最后的128M劃分到了high memory,為什么要這樣設(shè)計(jì)?原因是低內(nèi)存區(qū)頁表的映射關(guān)系是固定的,系統(tǒng)初始化時就建立了,內(nèi)核空間本來1G就小,還不靈活,當(dāng)然不行,所以留出128M來做兩件事:1.這部分空間可以通過頁表操作映射到高端物理地址,2.連續(xù)的虛擬地址空間可以映射到非連續(xù)的物理內(nèi)存。這在沒有大段連續(xù)的空閑物理地址時,是非常重要的。
x86-32上分區(qū)總結(jié)如下:

頁框:操作系統(tǒng)內(nèi)存管理方式有:段式、頁式、段頁式。Linux采用頁式內(nèi)存管理,頁是物理內(nèi)存管理的基本單位,每個內(nèi)存分區(qū)又由大量的頁框組成。內(nèi)核以struct page來描述頁框。頁框有很多屬性,這些屬性描述了這個頁框的狀態(tài)、用途等,例如是否被分配。
三者之間的關(guān)系如下圖所示:

介紹完節(jié)點(diǎn)、分區(qū)和頁框關(guān)系后,我們接著再看看頁、頁表、頁框的關(guān)系:
我們知道,CPU并不是直接訪問物理內(nèi)存地址,而是通過虛擬地址空間來間接的訪問物理內(nèi)存地址。操作系統(tǒng)為每一個正在執(zhí)行的進(jìn)程分配的一個虛擬地址空間(邏輯地址),在32位機(jī)上,其范圍從0 ~ 4G-1。操作系統(tǒng)通過將虛擬地址空間和物理內(nèi)存地址之間建立映射關(guān)系,讓CPU間接的訪問物理內(nèi)存地址。
頁:將進(jìn)程分配的虛擬地址空間劃分的塊,對應(yīng)的大小就叫頁面大小。
頁框:將內(nèi)存物理地址劃分的塊。
頁和頁框二者一一對應(yīng),一個頁放入一個頁框,(理論上)頁的大小和頁框的大小相等。
頁表:操作系統(tǒng)通過維護(hù)一張表,這張表上記錄了每一對頁和框的映射關(guān)系,這個表即頁表。頁表被放在物理內(nèi)存中,由操作系統(tǒng)維護(hù)。
三者關(guān)系關(guān)系如下圖所示:

兩個小例子來捋下他們之間的關(guān)系:
一、計(jì)算頁表占用的內(nèi)存大小:
已知條件:邏輯地址32位、頁面大小4KB、頁表項(xiàng)大小4B,按字節(jié)編址。

首先 32 位的虛擬地址可表示的進(jìn)程大小應(yīng)該是2^32B = 4GB(暫時別去想頁號P占多少位,W占多少位)。根據(jù)頁的定義和頁面大小的定義將進(jìn)程進(jìn)行分頁:
頁面的數(shù)目為:2^20頁, 所以頁表就需要4B*2^20 = 4MB的空間存儲。
二、物理地址訪問流程分析
首先通過計(jì)算得到CPU訪問的虛擬地址,虛擬地址是由頁表號+業(yè)內(nèi)偏移地址組成,把這個地址傳給頁表寄存器即MMU,它對應(yīng)到物理地址的頁框號,訪問物理地址找到框的起始地址,然后加上偏移,訪問最終物理地址。

注意,每個進(jìn)程都有頁表,頁表起始地址和頁表長度的信息在進(jìn)程不被CPU執(zhí)行的時候,存放在其PCB內(nèi)。
按照上述的過程,可以發(fā)現(xiàn),CPU對內(nèi)存的一次訪問動作需要訪問兩次物理內(nèi)存才能達(dá)到目的。
為了提升效率,為了提高CPU對內(nèi)存的訪問效率,在CPU第一次訪問內(nèi)存之前,加了一個快速緩沖區(qū)寄存器TLB(Translation Lookaside Buffer),TLB是MMU的核心部件,它緩存少量的虛擬地址與物理地址的轉(zhuǎn)換關(guān)系,是轉(zhuǎn)換表的Cache,俗稱“快表”。當(dāng)TLB中沒有緩沖對應(yīng)的地址轉(zhuǎn)換關(guān)系時,需要通過對內(nèi)存中轉(zhuǎn)換表(大多數(shù)處理器的轉(zhuǎn)換表為多級頁表)的訪問來獲得虛擬地址和物理地址的對應(yīng)關(guān)系,引出MMU的另一核心部件TTW(TranslationTable walk)。TTW成功后,結(jié)果應(yīng)寫入TLB中。TLB里面存放了近期訪問過的頁表項(xiàng)。當(dāng)CPU發(fā)起一次訪問時,先到TLB中查詢是否存在對應(yīng)的頁表項(xiàng),如果有就直接返回了。整個過程只需要訪問一次內(nèi)存。如圖:

這種方式極大的提高了CPU對內(nèi)存的訪問效率。然而這樣的方式還是存在弊端,在物理內(nèi)存中需要拿出至少1M的連續(xù)的內(nèi)存空間來存放頁表。注意關(guān)鍵字不是1M,而是連續(xù)的。
解決辦法是可以通過多級頁表的方式,將頁表分為多個部分,分別存放,這樣就不要求連續(xù)的整段內(nèi)存,只需要多個連續(xù)的小段內(nèi)存即可。

參考:
https://www.cnblogs.com/youngerchina/p/5624516.html
https://blog.csdn.net/displayMessage/article/details/80905810
http://www.it610.com/article/3744890.htm
