Linux虛擬內(nèi)存技術(shù)初窺

1. 為什么要用虛擬內(nèi)存

總所周知,從做系統(tǒng)的主要作用是對計(jì)算機(jī)資源的管理以及程序調(diào)度,者其中就包括對內(nèi)存的管理?,F(xiàn)在很多的系統(tǒng)都是用虛擬內(nèi)存技術(shù)來對內(nèi)存的管理,所謂虛擬內(nèi)存,就是一種讓應(yīng)用程序覺得它擁有一個(gè)很大的內(nèi)存可以使用,例如對于一個(gè)64位的操作系統(tǒng),操作系統(tǒng)會給應(yīng)用程序制造一種它可以有2^64Bytes那么大的內(nèi)存可以使用的假象,雖然實(shí)際情況可能是這個(gè)電腦上只有4G的內(nèi)存。
對于一個(gè)多任務(wù)操作系統(tǒng),如果不適用虛擬內(nèi)存,計(jì)算機(jī)所擁有的那點(diǎn)內(nèi)存顯然不夠分,雖然我們可以選擇增加物理內(nèi)存的方式讓程序擁有更多的內(nèi)存可以使用,但是內(nèi)存的價(jià)格畢竟在哪里。
另外,即便你并不在乎價(jià)格,多大的內(nèi)存都能隨便買得起,但也并不意味這你裝了多大內(nèi)存就有多少內(nèi)存可以使用,不同CPU的架構(gòu)限制了它對內(nèi)存地址的訪問能力。例如一個(gè)64位架構(gòu)的CPU可能它只實(shí)現(xiàn)了44位,那么意味著它能訪問的物理內(nèi)存只有2^44Bytes這么大。
除了上面所說的資源抽象的作用,虛擬內(nèi)存還具有以下兩個(gè)優(yōu)點(diǎn):

  1. 信息隔離:虛擬內(nèi)存使得每個(gè)進(jìn)程都有自己的一個(gè)地址空間,每個(gè)進(jìn)程之間不能相互訪問對方的地址空間,這就增加了安全性;
  2. 錯(cuò)誤隔離:每個(gè)進(jìn)程內(nèi)部的錯(cuò)誤只會影響到該進(jìn)程,而不會危及別的進(jìn)程。

2. 術(shù)語

2.1. 地址空間

地址空間簡單來說就是一個(gè)進(jìn)程能夠訪問的所有虛擬地址,例如在64位系統(tǒng)中一個(gè)程序擁有的地址空間為0~0xFFFFFFFFFFFFFFFF

2.2 虛擬地址

虛擬地址(Virtual Address,VA),就是地址空間中的任意一個(gè)地址;

2.3. 物理地址

物理地址(Physical Address,PA),CPU訪問內(nèi)存所使用的真實(shí)地址;

2.4 頁

虛擬內(nèi)存中一段連續(xù)的內(nèi)存區(qū)域,整個(gè)虛擬內(nèi)存被分成多個(gè)大小相等的頁,不同架構(gòu)的CPU定義的頁的大小可能不同,例如4KB、8KB等。

2.5 頁幀

物理內(nèi)存中一段連續(xù)的區(qū)域,整個(gè)物理內(nèi)存被分成多個(gè)大小相等的頁幀,不同架構(gòu)的CPU定義的頁幀的大小可能不同,例如4KB、8KB等。一般情況下頁和頁幀的大小是一樣的,但在某些架構(gòu)的CPU上頁和頁幀的大小可能不一樣。

2.4 頁表

保存虛擬地址與物理地址映射關(guān)系的一個(gè)表,Linux中頁表分為多級結(jié)構(gòu),每一級都占據(jù)整個(gè)頁幀。頁幀只存在與物理內(nèi)存上并且不能交換,因此頁幀的大小的大小其實(shí)也限制了地址空間的大小。例如一個(gè)64位的操作系統(tǒng),雖然理論上它的地址空間應(yīng)該是0-2^64 Byte,但是在頁幀大小為4KB,擁有三級頁表的情況下,地址空間只有0-2^39那么大。這是怎么算出來的呢?
在三級頁表中,這三級分別稱為PGD(Page Global Directory)、PMD(Page Middle Directory)和PTE(Page Table Entry),他們的關(guān)系如圖1所示,PGD指向PMD,PMD指向PTE,PTE最終指向頁幀。PGD和PMD中存儲的下一級的物理地址,而PTE中存儲的內(nèi)容包括PFN(Page Frame Number)、標(biāo)志位等信息。

圖1 頁表結(jié)構(gòu)示意圖

由于頁幀的大小已經(jīng)是4KB,64位系統(tǒng)中也表中的每一項(xiàng)大小為64位也就是8Byte,那么一個(gè)頁幀能存儲的表項(xiàng)的數(shù)目為512條。由于只有一個(gè)頁幀存儲PGD,那么只需要使用9位就能夠索引到該頁幀中的所有表項(xiàng),因此虛擬地址中使用9位表示PGD中某一項(xiàng)。同理,PMD與PTE也只用9位,因此PGD、PMD與PTE占了虛擬地址中的27位。當(dāng)最終通過PTE找到存儲數(shù)據(jù)的真正頁幀,由于該頁幀中保存的是實(shí)際的數(shù)據(jù),通常以Byte為最小地址索引單元,因此4KB就能分成1024*4這么多小塊,需要12位才能索引完,合起來就需要39位。為了能使用更大的地址空間,就需要通過采取更大頁幀或者增加頁表級數(shù)的方法,例如如果使用8KB的頁幀,則地址空間可以擴(kuò)展到43位,而如果再擴(kuò)展一級頁表,則可以有48位地址空間可以使用。

2. 怎么表示物理內(nèi)存

物理內(nèi)存分為NUMA(Non-Uniform Memory Access)和UMA(Uniform Memory Access)兩種類型,雖然我們通常認(rèn)為CPU訪問內(nèi)存的各個(gè)區(qū)域的代價(jià)是一樣的,但是有時(shí)候并不是這樣。在Linux中,將訪問代價(jià)一樣的內(nèi)存歸為一個(gè)Node,UMA只有一個(gè)Node,NUMA有多個(gè)Node,一般的PC都是UMA類型的。
由于架構(gòu)的限制,CPU并不能平等使用所有的內(nèi)存,例如某些DMA處理器只能訪問物理內(nèi)存開始的16M內(nèi)存。因此,需要將物理內(nèi)存分為不同的區(qū)(Zone),通常可分為以下三個(gè)不同的區(qū):ZONE_DMA、ZONE_NORMAL以及ZONE_HIGHMEM,每一個(gè)區(qū)都表示一塊連續(xù)的內(nèi)存。
而每個(gè)區(qū)可以分為一個(gè)個(gè)頁幀,因此,在Linux中,物理內(nèi)存的表示如下圖2所示。


圖2 Linux中物理內(nèi)存的表示

3. 怎么通過虛擬內(nèi)存地址找到物理內(nèi)存地址

物理地址和虛擬地址的映射是通過頁表來實(shí)現(xiàn)的。那么我們怎么樣才能通過頁表將虛擬地址轉(zhuǎn)化為物理地址呢?如圖3所示,下面簡要介紹下頁表是怎么工作的。



在Linux中,每個(gè)進(jìn)程有一個(gè)指向PGD的指針,通過該指針我們能找到PGD表。找到該P(yáng)GD后,通過所給的地址的指定9位(如圖3中的page index),我們可以找到該虛擬地址所屬于的PGD項(xiàng),該相中保存的是指向PMD的地址,這樣,我們就來到該虛擬地址所屬于的PMD中。與之前一樣,我們在PMD中通過pmd index找到了對應(yīng)的PTE的地址,我們通過pte index找到了該虛擬地址所映射的頁幀。最后,通過offset我們就能確定該虛擬地址所指向的是所找到頁幀的哪一字節(jié)。

4. 如何實(shí)現(xiàn)

1949年10月1日,新中國成立的開國大典,很少人知道,當(dāng)時(shí)天上飛過的不是26架戰(zhàn)機(jī),而是17架。那時(shí),我國總共有100多架戰(zhàn)機(jī),其中很多已經(jīng)破爛不堪,飛都很難飛起來,而且還是萬國牌。
如何讓場面看起來更壯觀些?
沉思良久后,周總理提出了一個(gè)建議:這17架飛機(jī)中有9架速度比較快,閱兵時(shí)讓它們飛前面,繞一圈后迅速回到隊(duì)伍最后面,這樣就能營造出一種有26架飛機(jī)參加閱兵式的感覺。

操作系統(tǒng)對內(nèi)存的操作和這個(gè)飛機(jī)飛兩遍的操作非常相似。讓多個(gè)虛擬在 不同時(shí)間段與同一個(gè)頁幀做映射,就能然人柑橘能使用的內(nèi)存比實(shí)際的大。
只是僅僅讓多個(gè)虛擬頁分別于頁幀分時(shí)映射還不行,還需要有一個(gè)地方用于保存他們各自的數(shù)據(jù),這個(gè)地方就是硬盤。比如某個(gè)市場只有一個(gè)攤位,張三、李四和王五三班倒的用這個(gè)攤位賣東西。他們?nèi)吮舜瞬⒉恢缹Ψ降拇嬖?,顯然,除了這個(gè)攤位,他們?nèi)吮仨氝€各種需要一個(gè)倉庫用于在他們不賣貨的時(shí)間段存放他們的貨物,否則如果他們都貨物都直接丟在攤位,那么張三很可能就把李四的東西給賣了。

如圖4所示,假設(shè)操作系統(tǒng)將兩個(gè)虛擬頁映射到了同一個(gè)頁幀,這兩個(gè)虛擬頁可以屬于同一個(gè)地址空間也可以屬于不同的地址空間,一般來說應(yīng)該屬于不同的地址空間,假設(shè)它們分別稱為P1和P2,那么從感覺上這兩個(gè)虛擬頁都是獨(dú)立的一塊內(nèi)存,雖然實(shí)際上他們映射的是同一個(gè)頁幀,假設(shè)這個(gè)頁幀成為F,但同一時(shí)間內(nèi)只能有一個(gè)虛擬頁和頁幀綁定。此外,P1和P2在磁盤上各自有著一款與它們自身大小相等的空間作為備份,假設(shè)分別是B1與B2。某一時(shí)刻,F(xiàn)存儲的是P1的內(nèi)容,現(xiàn)在程序訪問到了P2,由于P2的目前還沒和F綁定,就會觸發(fā)缺頁中斷(page fault)。操作系統(tǒng)先掛起當(dāng)前程序,然后中斷處理程序(page fault handler)就會將目前物理內(nèi)存幀內(nèi)的內(nèi)容存儲到磁盤B1,而把B2的內(nèi)容讀到F,然后將P2綁定到F,最后恢復(fù)被掛起的程序的執(zhí)行。通過這一換頁機(jī)制,程序就拿到了P2上的存儲的內(nèi)容。當(dāng)又需要P1的內(nèi)容的時(shí)候,同樣的方法得到,而應(yīng)用程序并不知道這些,在應(yīng)用程序看來,它需要的數(shù)據(jù)一值都在內(nèi)存中。

圖4 換頁機(jī)制

5. 總結(jié)

本文只是對虛擬內(nèi)存做了簡單的介紹,內(nèi)存是個(gè)有意思的東西,程序的一切操作都是圍繞它展開,理解了底層對內(nèi)存的操作,對于理解上層程序?qū)?nèi)存所做的各種操作也很有幫助。

歡1迎2關(guān)3注4個(gè)5人6公7眾8號:TensorBoy

最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
【社區(qū)內(nèi)容提示】社區(qū)部分內(nèi)容疑似由AI輔助生成,瀏覽時(shí)請結(jié)合常識與多方信息審慎甄別。
平臺聲明:文章內(nèi)容(如有圖片或視頻亦包括在內(nèi))由作者上傳并發(fā)布,文章內(nèi)容僅代表作者本人觀點(diǎn),簡書系信息發(fā)布平臺,僅提供信息存儲服務(wù)。

友情鏈接更多精彩內(nèi)容