从资源池和管理的角度理解物理内存
生活随笔
收集整理的這篇文章主要介紹了
从资源池和管理的角度理解物理内存
小編覺(jué)得挺不錯(cuò)的,現(xiàn)在分享給大家,幫大家做個(gè)參考.
早就想搞一下內(nèi)存問(wèn)題了!這次正趁著搞bigmemory內(nèi)核,可以寫(xiě)一篇文章了。本文旨在記錄,不包含細(xì)節(jié),細(xì)節(jié)的話,google,百度均可,很多人已經(jīng)寫(xiě)了不少了。我只是按照自己的理解記錄一下內(nèi)存的點(diǎn)點(diǎn)滴滴而已,沒(méi)有一家之言,不討論,不較真。
當(dāng)時(shí)的機(jī)器是為了執(zhí)行一個(gè)特定的任務(wù),但是這種存儲(chǔ)執(zhí)行模型作為的一個(gè)最簡(jiǎn)單的核心,為后代的逐步復(fù)雜化奠定了基礎(chǔ)。我的觀點(diǎn)還是,一個(gè)概念或者其它什么東西,之所以復(fù)雜是因?yàn)樗?jīng)得起復(fù)雜。羅馬帝國(guó)始終脫離不了城邦格局,它經(jīng)不起復(fù)雜,它崩潰了!
但是,這種模型有兩個(gè)顯而易見(jiàn)的缺點(diǎn),第一,很難滿足一個(gè)大內(nèi)存需求的任務(wù),第二,一分就是一個(gè)段,段必須處在一個(gè)連續(xù)的空間。
?????? 內(nèi)存頁(yè)面的概念被提出后,頁(yè)就成了分配內(nèi)存的最小單位,而MMU則成了為程序分配內(nèi)存的服務(wù)管理機(jī)構(gòu),有了這個(gè)新機(jī)構(gòu),應(yīng)用程序再也不用考慮物理內(nèi)存的位置的大小以及偏移問(wèn)題了。
?????? 虛擬內(nèi)存的提出是革命性的,在以前,程序不得不維護(hù)自己段寄存器,以明確自己所需內(nèi)存的位置,只要是有一個(gè)地址,就可以根據(jù)段寄存器知道它位于內(nèi)存中的什么地方,也就是說(shuō),那個(gè)時(shí)候,程序是直接使用物理內(nèi)存的。虛擬內(nèi)存出現(xiàn)后,MMU接管了內(nèi)存管理的一切,應(yīng)用程序不必關(guān)心內(nèi)存的位置和大小了。如果是32位系統(tǒng),那么程序被承諾可以使用高達(dá)4G的內(nèi)存,如果是64位系統(tǒng),...至于自己使用的內(nèi)存在什么位置,則不必關(guān)心,可用的4G內(nèi)存只是許諾,等到需要的時(shí)候MMU自然會(huì)給你,如果沒(méi)有空閑內(nèi)存,自然會(huì)給你個(gè)說(shuō)法。MMU作為一個(gè)仲裁和管理機(jī)構(gòu),前提是大家必須信任它!
?????? 如果說(shuō)初期的直接獨(dú)占使用物理內(nèi)存是王政時(shí)代, 段式管理是貴族寡頭時(shí)代的話,虛擬內(nèi)存管理則真正到了民主時(shí)代,各項(xiàng)機(jī)構(gòu)有條不紊運(yùn)行。
由于采用了MMU這個(gè)中間層,物理內(nèi)存不再和程序直接打交道,則物理內(nèi)存的形式就變得不再重要,它可以是內(nèi)存條,也可以是磁盤(pán),甚至可以是設(shè)備,只要MMU能給出合理的解釋,并且按照應(yīng)用程序訪問(wèn)內(nèi)存的規(guī)則來(lái)訪問(wèn)這些實(shí)體并能給出正確的結(jié)果即可。這就使得文件映射,設(shè)備映射成了可能。如下圖所示:
?????? 雖然說(shuō)“從虛擬內(nèi)存映射到物理內(nèi)存通過(guò)查表可以實(shí)現(xiàn)”,但是具體的查表過(guò)程卻非常復(fù)雜,并不是簡(jiǎn)單的一對(duì)一的映射這么實(shí)現(xiàn)的。實(shí)際的實(shí)現(xiàn)是通過(guò)一個(gè)多極頁(yè)表的方式實(shí)現(xiàn)的。所謂的多級(jí)頁(yè)表是將虛擬地址分為不同的部分,每一部分代表不同的索引。這樣就可以按照內(nèi)存的范圍進(jìn)行區(qū)域劃分,更好的進(jìn)行頁(yè)表的管理。具體的方法和圖示無(wú)須google,百度即可!
?????? 使用多級(jí)頁(yè)表并不是為了減少內(nèi)存使用,說(shuō)實(shí)話,如果把所有的4G映射都建立頁(yè)表項(xiàng)的話,采用兩極頁(yè)表還會(huì)浪費(fèi)頁(yè)目錄表占用的4K空間,然而并不能如此考慮問(wèn)題,內(nèi)存使用分布是不遵循冪率的,因此你不必考慮黑天鵝事件。大部分情況下,不會(huì)建立太多的頁(yè)表,即使建立1000個(gè)頁(yè)表,它也會(huì)多數(shù)承載于連續(xù)的頁(yè)目錄項(xiàng)中,很多的頁(yè)表是不需要分配內(nèi)存的。主旨就是,將管理結(jié)構(gòu)分級(jí)往前推,往前推,往前推!
?????? 本文最后會(huì)給出一個(gè)程序,讓你眼見(jiàn)為實(shí)地明白頁(yè)表到底占據(jù)多少空間以及內(nèi)存的分布如何影響頁(yè)表占據(jù)內(nèi)存空間的大小。
?????? 事實(shí)上,整體的換入換出模型更加適合虛擬化,所謂的虛擬化指的是全部的,包括CPU在內(nèi)的虛擬化。它不適合虛擬內(nèi)存,既然CPU都是分時(shí)處理不同進(jìn)程的,內(nèi)存為何就不能分頁(yè)面映射給不同的進(jìn)程呢?
a.管理成本: 是資源就要有效管理,而管理本身也是消耗資源的,它在各個(gè)系統(tǒng)上都有一個(gè)上限。
b.體系結(jié)構(gòu)的兼容性考慮: 如果說(shuō)從一張白紙重新作畫(huà),那再簡(jiǎn)單不過(guò)了,然而現(xiàn)實(shí)并非如此,總線寬度為了兼容性并不能隨意擴(kuò)展。
c.實(shí)現(xiàn)成本: 計(jì)算機(jī)上的任何概念都是一個(gè)有限集,更加明確的原則就是,它不要求100%的好,而是要求90%可用即可。
d.電梯效應(yīng): 超高層的摩天大樓不可能建造,并不是因?yàn)榈讓映休d不了上層的持續(xù)壓力,而是如果建成了高層大廈,建得越高,電梯占據(jù)的空間就越大,達(dá)到閥值后,電梯的空間將超越使用空間。這是管理成本的另一層含義,只是更加嚴(yán)重些!
即使不能使物理內(nèi)存無(wú)限大,也可以讓它更大,PAE就是這個(gè)想法的產(chǎn)物。
?????? 到此為止,可能你還是不明白32位的系統(tǒng)如何去識(shí)別4G以上的內(nèi)存。注意,MMU使用頁(yè)表來(lái)定位頁(yè)面的位置,只要頁(yè)表項(xiàng)能填入一個(gè)大于32位的數(shù)字,就能尋址到4G以上的內(nèi)存--因?yàn)?2位可以尋址4G(why?...),加上硬件地址總線寬度能超越32位,那就能定位到大于4G的內(nèi)存,定位到這個(gè)頁(yè)面后,將其映射回32位的某個(gè)地址即可。如下圖所示:
記住,物理內(nèi)存僅僅就是一個(gè)資源的角色,在不考慮兼容性以及管理成本的情況下,當(dāng)然越大越好,并非非要和虛擬地址空間一致。在32位系統(tǒng)中,進(jìn)程的虛擬地址空間永遠(yuǎn)都是32位也就是4G的,但是這4G空間的地址卻是可以映射到任意的物理地址空間,一切盡在MMU,說(shuō)白了就是,第一,頁(yè)表項(xiàng)的映射指示到了任意的物理頁(yè)面,第二就是地址總線的寬度允許尋址到那個(gè)位置(否則,雖然從程序上講不會(huì)出錯(cuò),但是在地址總線上發(fā)射地址的時(shí)候會(huì)發(fā)生回繞!)。程序員可以照著書(shū)上的例子寫(xiě)出代碼,但是沒(méi)有什么書(shū)教你在哪些機(jī)器上這些代碼可以得到你預(yù)期的結(jié)果!!
?????? 是時(shí)候說(shuō)一下Linux了,對(duì)于實(shí)踐者和懷疑論者以及書(shū)生乃至抑郁癥患者抑或精神病而言,沒(méi)有任何高談闊論可以比得上一個(gè)實(shí)際的例子了。
用戶態(tài)可以有自己的映射,內(nèi)核態(tài)的映射全部交給了內(nèi)核本身!內(nèi)核簡(jiǎn)化了,它可以用一種更加簡(jiǎn)單且高效的方式實(shí)現(xiàn)管理,那就是一一線性映射,也就是將一個(gè)連續(xù)的內(nèi)核地址空間,映射到一塊連續(xù)的物理地址空間,雖然最終的訪存還是需要MMU,但是起碼不需要做復(fù)雜的管理工作了。映射到哪塊連續(xù)的物理地址空間好呢?當(dāng)然是最初的空間好,因?yàn)閮?nèi)核的映射位置不能依賴物理地址空間的大小。
?????? 以上就是一一線性映射的由來(lái)!但是為了滿足動(dòng)態(tài)的內(nèi)核態(tài)服務(wù)的內(nèi)存需求,比如動(dòng)態(tài)插拔的內(nèi)核模塊,比如用戶系統(tǒng)調(diào)用的臨時(shí)需求,內(nèi)核的虛擬地址空間還要留下一部分用來(lái)映射這些動(dòng)態(tài)的數(shù)據(jù)。最終內(nèi)核態(tài)的虛擬地址空間的布局成了如下布局:
這樣的布局本身沒(méi)有什么問(wèn)題,特別是如果你理解Windows的自映射以及內(nèi)核分頁(yè)機(jī)制之后,你就會(huì)發(fā)現(xiàn)Linux的方式是多么的原生態(tài),多么的環(huán)保。然而這種方式有一個(gè)疑問(wèn)-現(xiàn)如今還不能成為問(wèn)題:
為了保持一一映射的關(guān)系,所有的一一映射的內(nèi)存必須獨(dú)占且常駐內(nèi)存,和最原始的馮諾依曼機(jī)器實(shí)現(xiàn)那種方式一樣,因此,Linux的一一映射方式真正回歸了原生態(tài),只是中間有一個(gè)MMU例行公事而已!
?????? 現(xiàn)在考慮PAE的模式!我討厭《尼羅河上的慘案》中那個(gè)穿西服的家伙那種方式!如果啟動(dòng)了PAE,意味著系統(tǒng)中存在大量的內(nèi)存頁(yè)面,為了管理這些頁(yè)面,Linux內(nèi)核必須為這些頁(yè)面建立結(jié)構(gòu)體,即struct page。Linux系統(tǒng)是按照伙伴系統(tǒng)分配page的,伙伴系統(tǒng)要求事先必須存在page的索引,因此必須要考慮page結(jié)構(gòu)體們占據(jù)的內(nèi)存空間。作為基礎(chǔ)管理數(shù)據(jù)結(jié)構(gòu),這些page結(jié)構(gòu)都處在內(nèi)核的一一映射地址空間,然而一一映射的地址空間大小是有限制的,即896M!按照一個(gè)page結(jié)構(gòu)體32字節(jié)大小來(lái)計(jì)算的話,你算一下能允許多少page被索引,記住,896M不能全都用于page結(jié)構(gòu),內(nèi)存管理只是Linux內(nèi)核的一部分而已,另外還有大頭戲,進(jìn)程管理!結(jié)果就是在現(xiàn)行的Linux內(nèi)存管理模式下,只能管理有限的page,因此你并不能安裝64G的內(nèi)存在Linux系統(tǒng)上。
?????? 但是,作為一個(gè)通用且前衛(wèi)的系統(tǒng),關(guān)鍵是Linus動(dòng)不動(dòng)就動(dòng)粗口的情形下,Linux有自己的解決方案,其中不外乎以下兩點(diǎn):
a.使用大頁(yè)面: 一般而言,一個(gè)頁(yè)面4K,這樣為了索引大內(nèi)存就需要大量的頁(yè)面,但是如果一個(gè)頁(yè)面4M或者2M的話,索引大量?jī)?nèi)存就不需要大量的頁(yè)面了,頁(yè)面數(shù)量減少了,頁(yè)面管理結(jié)構(gòu)所占據(jù)的內(nèi)存空間也就減少了!
b.使用獨(dú)立的4G/4G模式: 雖然大頁(yè)面可以緩解管理結(jié)構(gòu)占據(jù)內(nèi)存太大的問(wèn)題,但是并不能解決!Linux支持一種4G/4G模式,即不再將所有進(jìn)程的最上面1G的內(nèi)核空間共享,而是每個(gè)進(jìn)程的用戶態(tài)獨(dú)占4G虛擬地址空間,切換到內(nèi)核態(tài)時(shí),同時(shí)切換到另一個(gè)4G地址空間,即獨(dú)立的4G的內(nèi)核地址空間!內(nèi)核態(tài)不再借用用戶進(jìn)程地址空間,而是獨(dú)立出來(lái)一個(gè)4G空間來(lái)尋址,在X86上,意味著不管是系統(tǒng)調(diào)用,不管是中斷還是異常,陷入內(nèi)核時(shí),都要切換CR3寄存器,這意味著你要付出一些代價(jià)!切換CR3的代價(jià)是昂貴的,它不光是save/restore的代價(jià),更是取消了cache加速的代價(jià)!
[plain]?view plaincopy #include?<stdio.h>?? #include?<stdlib.h>?? #include?<sys/mman.h>?? ?? int?main(int?argc,?char?**argv)?? {?? ????int?i?=?0,?total?=?0;?? ????for?(i?=?0;?i?<?1024;?i?++)?{?? ????????int?j?=?0;?? ????????for?(j?=?0;?j?<?1024;?j++)?{?? ????????????//保證每一個(gè)頁(yè)表起碼有一個(gè)頁(yè)面被分配,這樣是為了填充滿整個(gè)頁(yè)目錄?? ????????????//所以要用FIX參數(shù),使用LOCK參數(shù)目的在于使其頁(yè)表項(xiàng)中有內(nèi)容,否則就是缺頁(yè)中斷按需分配了?? ????????????char?*p?=?(char?*)mmap(i*1024*4096+j*4096,?16,?PROT_READ|PROT_WRITE,?MAP_SHARED|MAP_ANONYMOUS|MAP_FIXED|MAP_LOCKED,?-1,?0);?? ????????????//注釋掉的是:隨機(jī)分配頁(yè)面,不必填充,每一個(gè)頁(yè)目錄項(xiàng)?? ????????????//char?*p?=?(char?*)mmap(NULL,?16,?PROT_READ|PROT_WRITE,?MAP_SHARED|MAP_ANONYMOUS|MAP_LOCKED,?-1,?0);?? ????????????if((int)p?!=?-1)?{?? ????????????????total?++;?? ????????????????*p?=?13;?? ????????????????printf("addr:%p??%d??%d\n",?p,?i,?j);?? ????????????????break;?? ????????????}?? ????????}?? ????}?? ????printf("total:%d\n",?total);?? ????sleep(10000);?? }??
執(zhí)行前,查看 /proc/meminfo 后,由于頁(yè)表分配在高端內(nèi)存,即896上的內(nèi)存(我的系統(tǒng)2000M內(nèi)存),其內(nèi)容為:
HighTotal:?????? 1628104 kB
HighFree:??????? 1261560 kB
執(zhí)行后,total數(shù)目為768,符合預(yù)期,因?yàn)樯?G的內(nèi)存屬于內(nèi)核空間,不能mmap。查看/proc/meminfo后,HIGH內(nèi)存減小,減小多少自己算
HighTotal:?????? 1628104 kB
HighFree:??????? 1255360 kB
如果不用FIX參數(shù),那么頁(yè)表項(xiàng)同樣也是建立那么多,在我測(cè)試下來(lái),還多了很多,1024個(gè)頁(yè)表項(xiàng)全部建立成功,但是,HIGH內(nèi)存占據(jù)反而減少了:
HighTotal:?????? 1628104 kB
HighFree:??????? 1257344 kB
這說(shuō)明內(nèi)存分配的布局,也就是頁(yè)表有與否,會(huì)影響管理成本!什么是High內(nèi)存,是大于896M的所有物理內(nèi)存!可用通過(guò)/proc/meminfo看出來(lái)!
?????? 實(shí)際上,很多技術(shù)都是基于概率的,都是追求90%的可用而不是100%的完美!為何大家不必為衛(wèi)星殘骸墜落地球而擔(dān)心,因?yàn)榈厍蛏?0%都是海洋,陸地上人類聚集的地點(diǎn)不足1%,所以砸中人的概率字計(jì)算吧。如果我被砸中了,算是我對(duì)較真的神詛咒的一種報(bào)應(yīng)吧,但是并不絕對(duì)!
?????? 按照局部性原理,一個(gè)CPU在同一時(shí)刻只能處理有限區(qū)域的內(nèi)存數(shù)據(jù)!時(shí)間比空間更重要,強(qiáng)勁的CPU要比64位的虛擬地址空間更加有用,虛擬地址空間并不是實(shí)際落實(shí)的物理地內(nèi)存空間,效率和速度體現(xiàn)在落實(shí)的物理內(nèi)存上!即使是物理內(nèi)存的因素,安裝比較大的物理內(nèi)存更多的是在于減少換入換出開(kāi)銷,而不是為了滿足同時(shí)訪問(wèn)大量?jī)?nèi)存的需求。即使有同時(shí)需要大量?jī)?nèi)存的程序,也可以通過(guò)并發(fā)處理,通過(guò)多核來(lái)將其平坦化!
?????? 我并不詆毀64位,只是覺(jué)得按照資源池的概念,你只需要在乎物理內(nèi)存,而無(wú)需在乎虛擬內(nèi)存!別提數(shù)據(jù)庫(kù),我討厭數(shù)據(jù)庫(kù),因?yàn)樗偸菫樽约赫紦?jù)大量磁盤(pán)需要很高的CPU處理能力而狂呼資源不夠,但是實(shí)際上早期的ER模型并不適合現(xiàn)在的大數(shù)據(jù)處理!是數(shù)據(jù)庫(kù)本身的問(wèn)題,而不是處理資源不夠!
?????? 與其64位,不如來(lái)個(gè)8核,已經(jīng)有了8核,32位夠了! 創(chuàng)作挑戰(zhàn)賽新人創(chuàng)作獎(jiǎng)勵(lì)來(lái)咯,堅(jiān)持創(chuàng)作打卡瓜分現(xiàn)金大獎(jiǎng)
1.最簡(jiǎn)單的內(nèi)存使用
最簡(jiǎn)單的模型是馮.諾依曼提出的原始模型,簡(jiǎn)單的把數(shù)據(jù)和指令存放在內(nèi)存中,然后機(jī)器從內(nèi)存中取出指令和數(shù)據(jù)進(jìn)行計(jì)算,如下圖所示:當(dāng)時(shí)的機(jī)器是為了執(zhí)行一個(gè)特定的任務(wù),但是這種存儲(chǔ)執(zhí)行模型作為的一個(gè)最簡(jiǎn)單的核心,為后代的逐步復(fù)雜化奠定了基礎(chǔ)。我的觀點(diǎn)還是,一個(gè)概念或者其它什么東西,之所以復(fù)雜是因?yàn)樗?jīng)得起復(fù)雜。羅馬帝國(guó)始終脫離不了城邦格局,它經(jīng)不起復(fù)雜,它崩潰了!
2.分時(shí)系統(tǒng)內(nèi)存模型
2.1.計(jì)劃
一臺(tái)機(jī)器執(zhí)行一個(gè)任務(wù),太浪費(fèi)資源了,略過(guò)中間的掙扎,直接到了分時(shí)系統(tǒng)時(shí)代,一臺(tái)機(jī)器可以執(zhí)行多個(gè)任務(wù)了,如果切換機(jī)制足夠好,這些任務(wù)可以滿足低延遲需求。馮諾依曼機(jī)器的核心是處理器和內(nèi)存,處理器沿時(shí)間軸推進(jìn),內(nèi)存則空間平面上展開(kāi),分時(shí)系統(tǒng)在時(shí)間軸上分割了多個(gè)任務(wù),它需要在空間平面上同樣分割多個(gè)任務(wù),于是內(nèi)存變成了一種共享的資源,如何在多個(gè)任務(wù)之間分配這個(gè)單一的共享的內(nèi)存資源成了后來(lái)技術(shù)發(fā)展的重軸戲。2.2.段式內(nèi)存模型
段式內(nèi)存模型將一個(gè)程序劃分為不同的段,不同任務(wù)的不同段處在內(nèi)存的不同段當(dāng)中,如下圖所示:但是,這種模型有兩個(gè)顯而易見(jiàn)的缺點(diǎn),第一,很難滿足一個(gè)大內(nèi)存需求的任務(wù),第二,一分就是一個(gè)段,段必須處在一個(gè)連續(xù)的空間。
2.3.虛擬內(nèi)存
一個(gè)任務(wù)所需要的內(nèi)存大小以及位置不應(yīng)該依賴其它任務(wù)的內(nèi)存的大小和位置,并且內(nèi)存的位置也不應(yīng)該是永久性的,任務(wù)使用內(nèi)存就應(yīng)該和人們使用公共廁所一樣。程序任務(wù)只管自己的計(jì)算邏輯,用到內(nèi)存的時(shí)候,不必自己操心,應(yīng)該有一個(gè)服務(wù)機(jī)構(gòu)為其現(xiàn)場(chǎng)分配內(nèi)存,分配多少算好呢,答案就是就可能少,按照基本單位分配,也就是說(shuō)只分配程序現(xiàn)在用的那個(gè)內(nèi)存,即便說(shuō)馬上就要用另一塊內(nèi)存,那也要等到時(shí)候再說(shuō),這樣就做到了公平和高效!既滿足了盡可能多的程序的內(nèi)存需求,又不會(huì)浪費(fèi)任何不會(huì)用到的內(nèi)存。?????? 內(nèi)存頁(yè)面的概念被提出后,頁(yè)就成了分配內(nèi)存的最小單位,而MMU則成了為程序分配內(nèi)存的服務(wù)管理機(jī)構(gòu),有了這個(gè)新機(jī)構(gòu),應(yīng)用程序再也不用考慮物理內(nèi)存的位置的大小以及偏移問(wèn)題了。
?????? 虛擬內(nèi)存的提出是革命性的,在以前,程序不得不維護(hù)自己段寄存器,以明確自己所需內(nèi)存的位置,只要是有一個(gè)地址,就可以根據(jù)段寄存器知道它位于內(nèi)存中的什么地方,也就是說(shuō),那個(gè)時(shí)候,程序是直接使用物理內(nèi)存的。虛擬內(nèi)存出現(xiàn)后,MMU接管了內(nèi)存管理的一切,應(yīng)用程序不必關(guān)心內(nèi)存的位置和大小了。如果是32位系統(tǒng),那么程序被承諾可以使用高達(dá)4G的內(nèi)存,如果是64位系統(tǒng),...至于自己使用的內(nèi)存在什么位置,則不必關(guān)心,可用的4G內(nèi)存只是許諾,等到需要的時(shí)候MMU自然會(huì)給你,如果沒(méi)有空閑內(nèi)存,自然會(huì)給你個(gè)說(shuō)法。MMU作為一個(gè)仲裁和管理機(jī)構(gòu),前提是大家必須信任它!
?????? 如果說(shuō)初期的直接獨(dú)占使用物理內(nèi)存是王政時(shí)代, 段式管理是貴族寡頭時(shí)代的話,虛擬內(nèi)存管理則真正到了民主時(shí)代,各項(xiàng)機(jī)構(gòu)有條不紊運(yùn)行。
2.4.頁(yè)式內(nèi)存模型
頁(yè)式模型顧名思義就是以頁(yè)面為基礎(chǔ)進(jìn)行內(nèi)存管理,注意,最終的內(nèi)存頁(yè)面并不直接和程序打交道,它通過(guò)MMU和程序打交道。由于有了MMU這個(gè)中間層,它負(fù)責(zé)將一個(gè)程序的虛擬內(nèi)存地址映射到實(shí)際的物理地址,怎么做到的呢?當(dāng)然是通過(guò)一張表,即頁(yè)表來(lái)查詢的。由于采用了MMU這個(gè)中間層,物理內(nèi)存不再和程序直接打交道,則物理內(nèi)存的形式就變得不再重要,它可以是內(nèi)存條,也可以是磁盤(pán),甚至可以是設(shè)備,只要MMU能給出合理的解釋,并且按照應(yīng)用程序訪問(wèn)內(nèi)存的規(guī)則來(lái)訪問(wèn)這些實(shí)體并能給出正確的結(jié)果即可。這就使得文件映射,設(shè)備映射成了可能。如下圖所示:
?????? 雖然說(shuō)“從虛擬內(nèi)存映射到物理內(nèi)存通過(guò)查表可以實(shí)現(xiàn)”,但是具體的查表過(guò)程卻非常復(fù)雜,并不是簡(jiǎn)單的一對(duì)一的映射這么實(shí)現(xiàn)的。實(shí)際的實(shí)現(xiàn)是通過(guò)一個(gè)多極頁(yè)表的方式實(shí)現(xiàn)的。所謂的多級(jí)頁(yè)表是將虛擬地址分為不同的部分,每一部分代表不同的索引。這樣就可以按照內(nèi)存的范圍進(jìn)行區(qū)域劃分,更好的進(jìn)行頁(yè)表的管理。具體的方法和圖示無(wú)須google,百度即可!
附:一些細(xì)節(jié)-為何采用多級(jí)頁(yè)表
在實(shí)際的實(shí)現(xiàn)中,為何要使用多級(jí)頁(yè)表而不是單級(jí)頁(yè)表呢?這是從管理成本來(lái)考慮的。由于是一個(gè)表,那么它便有連續(xù)內(nèi)存存儲(chǔ)的需求,這樣才好根據(jù)索引來(lái)快速定位。如果是單層頁(yè)表,那么即使一個(gè)頁(yè)面被分配,也需要建立整個(gè)頁(yè)表,32位的情況下以4K頁(yè)面為例,需要20位要尋址頁(yè)面基地址,20位的話單級(jí)頁(yè)表需要一下子建立4M大小的頁(yè)表。?????? 使用多級(jí)頁(yè)表并不是為了減少內(nèi)存使用,說(shuō)實(shí)話,如果把所有的4G映射都建立頁(yè)表項(xiàng)的話,采用兩極頁(yè)表還會(huì)浪費(fèi)頁(yè)目錄表占用的4K空間,然而并不能如此考慮問(wèn)題,內(nèi)存使用分布是不遵循冪率的,因此你不必考慮黑天鵝事件。大部分情況下,不會(huì)建立太多的頁(yè)表,即使建立1000個(gè)頁(yè)表,它也會(huì)多數(shù)承載于連續(xù)的頁(yè)目錄項(xiàng)中,很多的頁(yè)表是不需要分配內(nèi)存的。主旨就是,將管理結(jié)構(gòu)分級(jí)往前推,往前推,往前推!
?????? 本文最后會(huì)給出一個(gè)程序,讓你眼見(jiàn)為實(shí)地明白頁(yè)表到底占據(jù)多少空間以及內(nèi)存的分布如何影響頁(yè)表占據(jù)內(nèi)存空間的大小。
2.5.換入換出機(jī)制
有點(diǎn)懵了,怎么現(xiàn)在才開(kāi)始說(shuō)換入換出,是不是順序弄亂了,不是說(shuō)很早的UNIX時(shí)代就有換入換出了么?如今Linux還保留著swap進(jìn)程(其實(shí)是內(nèi)核線程,因?yàn)榭傆腥溯^真,說(shuō)什么內(nèi)核線程不能叫做進(jìn)程,看書(shū)看多了)這個(gè)名稱。非也,不是弄錯(cuò)了,而是我想基于交換機(jī)制來(lái)談一下虛擬內(nèi)存的意義,并不是講換入換出機(jī)制本身。2.5.1.整體換入換出
這是最實(shí)際不過(guò)的了,分時(shí)系統(tǒng)將一個(gè)進(jìn)程拉到前臺(tái)來(lái)運(yùn)行的時(shí)候,將該進(jìn)程的映像從磁盤(pán)換到內(nèi)存,同時(shí)將正在執(zhí)行的進(jìn)程換出到磁盤(pán)。雖然簡(jiǎn)單,但是卻沒(méi)有后續(xù)的可擴(kuò)展性。這其實(shí)是基于最初的內(nèi)存模型修正的,而絲毫沒(méi)有用到虛擬內(nèi)存的優(yōu)勢(shì)。虛擬內(nèi)存不關(guān)心進(jìn)程,不關(guān)心內(nèi)存頁(yè)面的位置,切斷了物理內(nèi)存和進(jìn)程的關(guān)系,只關(guān)注頁(yè)面本身,頁(yè)面的內(nèi)容可以來(lái)自計(jì)算,來(lái)自文件,來(lái)自設(shè)備,...?????? 事實(shí)上,整體的換入換出模型更加適合虛擬化,所謂的虛擬化指的是全部的,包括CPU在內(nèi)的虛擬化。它不適合虛擬內(nèi)存,既然CPU都是分時(shí)處理不同進(jìn)程的,內(nèi)存為何就不能分頁(yè)面映射給不同的進(jìn)程呢?
2.5.2.頁(yè)面換入換出
由整體換入換出的弊端引起的直接結(jié)果就是頁(yè)面的換入換出。一個(gè)頁(yè)面就是一個(gè)頁(yè)面,它不和進(jìn)程進(jìn)行關(guān)聯(lián),只和頁(yè)表項(xiàng)進(jìn)行關(guān)聯(lián),這是虛擬內(nèi)存管理高效性和公平性之根本。單獨(dú)頁(yè)面的管理以及基于頁(yè)面的換入換出機(jī)制,虛擬內(nèi)存之根本!3.物理內(nèi)存的角色
在使用虛擬內(nèi)存之后,物理內(nèi)存的角色已經(jīng)不再像早期那樣重要,它退化成了一個(gè)資源的角色,作為一種資源,原則上它可以是無(wú)限大的,而且越大越好,但是受制于以下的因素:a.管理成本: 是資源就要有效管理,而管理本身也是消耗資源的,它在各個(gè)系統(tǒng)上都有一個(gè)上限。
b.體系結(jié)構(gòu)的兼容性考慮: 如果說(shuō)從一張白紙重新作畫(huà),那再簡(jiǎn)單不過(guò)了,然而現(xiàn)實(shí)并非如此,總線寬度為了兼容性并不能隨意擴(kuò)展。
c.實(shí)現(xiàn)成本: 計(jì)算機(jī)上的任何概念都是一個(gè)有限集,更加明確的原則就是,它不要求100%的好,而是要求90%可用即可。
d.電梯效應(yīng): 超高層的摩天大樓不可能建造,并不是因?yàn)榈讓映休d不了上層的持續(xù)壓力,而是如果建成了高層大廈,建得越高,電梯占據(jù)的空間就越大,達(dá)到閥值后,電梯的空間將超越使用空間。這是管理成本的另一層含義,只是更加嚴(yán)重些!
即使不能使物理內(nèi)存無(wú)限大,也可以讓它更大,PAE就是這個(gè)想法的產(chǎn)物。
4.映射到物理內(nèi)存
物理內(nèi)存并非一定要和虛擬內(nèi)存的大小一致,如果是這樣的話,虛擬內(nèi)存的意義是不明顯的。以32位系統(tǒng)為例,N個(gè)進(jìn)程均被許諾有4G內(nèi)存,然而它們共享4G物理內(nèi)存,誰(shuí)也不能同時(shí)用盡所有內(nèi)存,然而如果真的有這樣需求的進(jìn)程怎么辦?那只能頻繁的換入換出了,雖然也是可以實(shí)現(xiàn),但是更好的做法就是安裝N*4G的內(nèi)存,可是這樣的話好像又退回到了段式管理,只是內(nèi)存的實(shí)際位置不再確定,只是將基于段的管理改成了粒度更細(xì)的頁(yè)式管理而已。由于N的不確定性以及內(nèi)存使用的不確定性,沒(méi)有必要安裝那么大的內(nèi)存,最終的方案就是安裝稍微大一些的內(nèi)存,比如16G,32G,64G的內(nèi)存,機(jī)器就足以飛起來(lái)了!?????? 到此為止,可能你還是不明白32位的系統(tǒng)如何去識(shí)別4G以上的內(nèi)存。注意,MMU使用頁(yè)表來(lái)定位頁(yè)面的位置,只要頁(yè)表項(xiàng)能填入一個(gè)大于32位的數(shù)字,就能尋址到4G以上的內(nèi)存--因?yàn)?2位可以尋址4G(why?...),加上硬件地址總線寬度能超越32位,那就能定位到大于4G的內(nèi)存,定位到這個(gè)頁(yè)面后,將其映射回32位的某個(gè)地址即可。如下圖所示:
記住,物理內(nèi)存僅僅就是一個(gè)資源的角色,在不考慮兼容性以及管理成本的情況下,當(dāng)然越大越好,并非非要和虛擬地址空間一致。在32位系統(tǒng)中,進(jìn)程的虛擬地址空間永遠(yuǎn)都是32位也就是4G的,但是這4G空間的地址卻是可以映射到任意的物理地址空間,一切盡在MMU,說(shuō)白了就是,第一,頁(yè)表項(xiàng)的映射指示到了任意的物理頁(yè)面,第二就是地址總線的寬度允許尋址到那個(gè)位置(否則,雖然從程序上講不會(huì)出錯(cuò),但是在地址總線上發(fā)射地址的時(shí)候會(huì)發(fā)生回繞!)。程序員可以照著書(shū)上的例子寫(xiě)出代碼,但是沒(méi)有什么書(shū)教你在哪些機(jī)器上這些代碼可以得到你預(yù)期的結(jié)果!!
5.Linux上的實(shí)現(xiàn)與PAE/PSE相關(guān)
上面說(shuō)的加大物理內(nèi)存供應(yīng)的說(shuō)法,其實(shí)有一種實(shí)現(xiàn)那就是PAE。PAE是什么,google吧,如果怕google動(dòng)不動(dòng)就RESET,那么百度也能得到結(jié)果!PAE允許你尋址36位的物理地址空間!也就是說(shuō)允許你安裝64G的內(nèi)存。按照物理內(nèi)存只是資源池的概念,所有的32位進(jìn)程共享所有安裝的物理內(nèi)存,每一個(gè)進(jìn)程尋址32位虛擬地址,通過(guò)MMU實(shí)際可以訪問(wèn)36位的物理地址。?????? 是時(shí)候說(shuō)一下Linux了,對(duì)于實(shí)踐者和懷疑論者以及書(shū)生乃至抑郁癥患者抑或精神病而言,沒(méi)有任何高談闊論可以比得上一個(gè)實(shí)際的例子了。
5.1.Linux的地址映射方式
Linux采用了一種極其簡(jiǎn)單的地址映射方式,那就是將內(nèi)核空間的代碼以及數(shù)據(jù)和實(shí)際的用戶進(jìn)程隔離開(kāi)來(lái),怎么個(gè)簡(jiǎn)單法呢?很簡(jiǎn)單,那就是將進(jìn)程的地址空間劃分為用戶態(tài)的3G和內(nèi)核態(tài)的1G,所謂的用戶態(tài)就是非特權(quán)態(tài),對(duì)于那些愛(ài)看書(shū)的優(yōu)秀學(xué)生而言,他們熟悉的語(yǔ)言是第3特權(quán)護(hù)環(huán),不管怎么說(shuō),反正就是進(jìn)程可見(jiàn)的數(shù)據(jù)和代碼的地址空間!用戶態(tài)的地址空間映射,內(nèi)核不過(guò)問(wèn),而內(nèi)核態(tài)的映射,所有的用戶態(tài)共享,作為一個(gè)管理機(jī)構(gòu),它是唯一的,如下圖所示:用戶態(tài)可以有自己的映射,內(nèi)核態(tài)的映射全部交給了內(nèi)核本身!內(nèi)核簡(jiǎn)化了,它可以用一種更加簡(jiǎn)單且高效的方式實(shí)現(xiàn)管理,那就是一一線性映射,也就是將一個(gè)連續(xù)的內(nèi)核地址空間,映射到一塊連續(xù)的物理地址空間,雖然最終的訪存還是需要MMU,但是起碼不需要做復(fù)雜的管理工作了。映射到哪塊連續(xù)的物理地址空間好呢?當(dāng)然是最初的空間好,因?yàn)閮?nèi)核的映射位置不能依賴物理地址空間的大小。
?????? 以上就是一一線性映射的由來(lái)!但是為了滿足動(dòng)態(tài)的內(nèi)核態(tài)服務(wù)的內(nèi)存需求,比如動(dòng)態(tài)插拔的內(nèi)核模塊,比如用戶系統(tǒng)調(diào)用的臨時(shí)需求,內(nèi)核的虛擬地址空間還要留下一部分用來(lái)映射這些動(dòng)態(tài)的數(shù)據(jù)。最終內(nèi)核態(tài)的虛擬地址空間的布局成了如下布局:
這樣的布局本身沒(méi)有什么問(wèn)題,特別是如果你理解Windows的自映射以及內(nèi)核分頁(yè)機(jī)制之后,你就會(huì)發(fā)現(xiàn)Linux的方式是多么的原生態(tài),多么的環(huán)保。然而這種方式有一個(gè)疑問(wèn)-現(xiàn)如今還不能成為問(wèn)題:
為了保持一一映射的關(guān)系,所有的一一映射的內(nèi)存必須獨(dú)占且常駐內(nèi)存,和最原始的馮諾依曼機(jī)器實(shí)現(xiàn)那種方式一樣,因此,Linux的一一映射方式真正回歸了原生態(tài),只是中間有一個(gè)MMU例行公事而已!
?????? 現(xiàn)在考慮PAE的模式!我討厭《尼羅河上的慘案》中那個(gè)穿西服的家伙那種方式!如果啟動(dòng)了PAE,意味著系統(tǒng)中存在大量的內(nèi)存頁(yè)面,為了管理這些頁(yè)面,Linux內(nèi)核必須為這些頁(yè)面建立結(jié)構(gòu)體,即struct page。Linux系統(tǒng)是按照伙伴系統(tǒng)分配page的,伙伴系統(tǒng)要求事先必須存在page的索引,因此必須要考慮page結(jié)構(gòu)體們占據(jù)的內(nèi)存空間。作為基礎(chǔ)管理數(shù)據(jù)結(jié)構(gòu),這些page結(jié)構(gòu)都處在內(nèi)核的一一映射地址空間,然而一一映射的地址空間大小是有限制的,即896M!按照一個(gè)page結(jié)構(gòu)體32字節(jié)大小來(lái)計(jì)算的話,你算一下能允許多少page被索引,記住,896M不能全都用于page結(jié)構(gòu),內(nèi)存管理只是Linux內(nèi)核的一部分而已,另外還有大頭戲,進(jìn)程管理!結(jié)果就是在現(xiàn)行的Linux內(nèi)存管理模式下,只能管理有限的page,因此你并不能安裝64G的內(nèi)存在Linux系統(tǒng)上。
?????? 但是,作為一個(gè)通用且前衛(wèi)的系統(tǒng),關(guān)鍵是Linus動(dòng)不動(dòng)就動(dòng)粗口的情形下,Linux有自己的解決方案,其中不外乎以下兩點(diǎn):
a.使用大頁(yè)面: 一般而言,一個(gè)頁(yè)面4K,這樣為了索引大內(nèi)存就需要大量的頁(yè)面,但是如果一個(gè)頁(yè)面4M或者2M的話,索引大量?jī)?nèi)存就不需要大量的頁(yè)面了,頁(yè)面數(shù)量減少了,頁(yè)面管理結(jié)構(gòu)所占據(jù)的內(nèi)存空間也就減少了!
b.使用獨(dú)立的4G/4G模式: 雖然大頁(yè)面可以緩解管理結(jié)構(gòu)占據(jù)內(nèi)存太大的問(wèn)題,但是并不能解決!Linux支持一種4G/4G模式,即不再將所有進(jìn)程的最上面1G的內(nèi)核空間共享,而是每個(gè)進(jìn)程的用戶態(tài)獨(dú)占4G虛擬地址空間,切換到內(nèi)核態(tài)時(shí),同時(shí)切換到另一個(gè)4G地址空間,即獨(dú)立的4G的內(nèi)核地址空間!內(nèi)核態(tài)不再借用用戶進(jìn)程地址空間,而是獨(dú)立出來(lái)一個(gè)4G空間來(lái)尋址,在X86上,意味著不管是系統(tǒng)調(diào)用,不管是中斷還是異常,陷入內(nèi)核時(shí),都要切換CR3寄存器,這意味著你要付出一些代價(jià)!切換CR3的代價(jià)是昂貴的,它不光是save/restore的代價(jià),更是取消了cache加速的代價(jià)!
5.2.Linux內(nèi)核的管理成本
說(shuō)白了,Linux內(nèi)核的管理成本太昂貴,很多的管理數(shù)據(jù)結(jié)構(gòu)都要占據(jù)內(nèi)核的一一線性映射的896M的空間!雖然進(jìn)程結(jié)構(gòu)task_struct結(jié)構(gòu)體不大,但是896M除以sizeof(struct task_struct)的話,也不是一個(gè)很大的數(shù),再加上CR3指向的頁(yè)目錄頁(yè)表等,896M真的容不下什么太多的內(nèi)容!最根本的限制那就是這種機(jī)制限制了系統(tǒng)同時(shí)運(yùn)行進(jìn)程的數(shù)量!但是,Linux內(nèi)核的這種原始內(nèi)存映射的優(yōu)點(diǎn)也顯而易見(jiàn),那就是社區(qū)大牛們總是可以設(shè)計(jì)出一些精巧的數(shù)據(jù)結(jié)構(gòu),往往在惡劣環(huán)境下寫(xiě)出的代碼,一定是高效的代碼,這同時(shí)也是微軟的信條!5.3.看一段代碼展示管理成本
是時(shí)候展示一個(gè)簡(jiǎn)單的代碼了。該代碼讓你看一下管理成本,雖然很簡(jiǎn)單,但是可以讓你看到一個(gè)進(jìn)程本身雖然不占據(jù)什么內(nèi)存空間,但是光其頁(yè)表就占據(jù)大量的內(nèi)存。在展示代碼之前,先看一個(gè)Linux內(nèi)核的編譯宏HIGHPTE,該宏決定你能不能將頁(yè)表這種吃內(nèi)存的管理結(jié)構(gòu)分配在高端內(nèi)存,即大于896M的物理內(nèi)存,也就是說(shuō)如果你啟用了該宏,就不必在一一線性映射區(qū)域分配頁(yè)表!我的系統(tǒng)啟用了該宏,意味著頁(yè)表都盡量分配在高端內(nèi)存。以下是代碼:[plain]?view plaincopy
執(zhí)行前,查看 /proc/meminfo 后,由于頁(yè)表分配在高端內(nèi)存,即896上的內(nèi)存(我的系統(tǒng)2000M內(nèi)存),其內(nèi)容為:
HighTotal:?????? 1628104 kB
HighFree:??????? 1261560 kB
執(zhí)行后,total數(shù)目為768,符合預(yù)期,因?yàn)樯?G的內(nèi)存屬于內(nèi)核空間,不能mmap。查看/proc/meminfo后,HIGH內(nèi)存減小,減小多少自己算
HighTotal:?????? 1628104 kB
HighFree:??????? 1255360 kB
如果不用FIX參數(shù),那么頁(yè)表項(xiàng)同樣也是建立那么多,在我測(cè)試下來(lái),還多了很多,1024個(gè)頁(yè)表項(xiàng)全部建立成功,但是,HIGH內(nèi)存占據(jù)反而減少了:
HighTotal:?????? 1628104 kB
HighFree:??????? 1257344 kB
這說(shuō)明內(nèi)存分配的布局,也就是頁(yè)表有與否,會(huì)影響管理成本!什么是High內(nèi)存,是大于896M的所有物理內(nèi)存!可用通過(guò)/proc/meminfo看出來(lái)!
6.IT技術(shù)并不絕對(duì)
到底安裝多少物理內(nèi)存算多,可以算出來(lái)嗎?IT技術(shù)算精確技術(shù)嗎?我不覺(jué)得喜歡較真的人能徹底理解TCP。衛(wèi)星技術(shù)要比IT技術(shù)高深TMD的多了,怎么沒(méi)有人能預(yù)測(cè)出歐洲衛(wèi)星殘骸墜落地球的具體地點(diǎn),追究TCP重傳具體時(shí)間具體算法的人可能要徹夜計(jì)算衛(wèi)星殘骸墜落地點(diǎn)了,由于精神高度緊張,猝死的可能性比猜中50%的可能性更高!?????? 實(shí)際上,很多技術(shù)都是基于概率的,都是追求90%的可用而不是100%的完美!為何大家不必為衛(wèi)星殘骸墜落地球而擔(dān)心,因?yàn)榈厍蛏?0%都是海洋,陸地上人類聚集的地點(diǎn)不足1%,所以砸中人的概率字計(jì)算吧。如果我被砸中了,算是我對(duì)較真的神詛咒的一種報(bào)應(yīng)吧,但是并不絕對(duì)!
7.64位,TMD64位!
曾經(jīng),大家不約而同地使用64位系統(tǒng),實(shí)際上沒(méi)有誰(shuí)的系統(tǒng)可以用到大內(nèi)存,就算吃內(nèi)存的游戲,32位也已經(jīng)足夠,關(guān)鍵的是能申請(qǐng)到物理內(nèi)存。只要物理內(nèi)存大即可,虛擬內(nèi)存有誰(shuí)會(huì)用到那么大呢?你更多的受益于多核而不是64位。我們對(duì)時(shí)間的感覺(jué)要比對(duì)空間的感覺(jué)敏感得多。?????? 按照局部性原理,一個(gè)CPU在同一時(shí)刻只能處理有限區(qū)域的內(nèi)存數(shù)據(jù)!時(shí)間比空間更重要,強(qiáng)勁的CPU要比64位的虛擬地址空間更加有用,虛擬地址空間并不是實(shí)際落實(shí)的物理地內(nèi)存空間,效率和速度體現(xiàn)在落實(shí)的物理內(nèi)存上!即使是物理內(nèi)存的因素,安裝比較大的物理內(nèi)存更多的是在于減少換入換出開(kāi)銷,而不是為了滿足同時(shí)訪問(wèn)大量?jī)?nèi)存的需求。即使有同時(shí)需要大量?jī)?nèi)存的程序,也可以通過(guò)并發(fā)處理,通過(guò)多核來(lái)將其平坦化!
?????? 我并不詆毀64位,只是覺(jué)得按照資源池的概念,你只需要在乎物理內(nèi)存,而無(wú)需在乎虛擬內(nèi)存!別提數(shù)據(jù)庫(kù),我討厭數(shù)據(jù)庫(kù),因?yàn)樗偸菫樽约赫紦?jù)大量磁盤(pán)需要很高的CPU處理能力而狂呼資源不夠,但是實(shí)際上早期的ER模型并不適合現(xiàn)在的大數(shù)據(jù)處理!是數(shù)據(jù)庫(kù)本身的問(wèn)題,而不是處理資源不夠!
?????? 與其64位,不如來(lái)個(gè)8核,已經(jīng)有了8核,32位夠了! 創(chuàng)作挑戰(zhàn)賽新人創(chuàng)作獎(jiǎng)勵(lì)來(lái)咯,堅(jiān)持創(chuàng)作打卡瓜分現(xiàn)金大獎(jiǎng)
總結(jié)
以上是生活随笔為你收集整理的从资源池和管理的角度理解物理内存的全部?jī)?nèi)容,希望文章能夠幫你解決所遇到的問(wèn)題。
- 上一篇: SQL优化案例-自定义函数索引(五)
- 下一篇: 阵列信号处理复习