全面解析虛擬內(nèi)存
一個(gè)系統(tǒng)中的進(jìn)程是與其他進(jìn)程共享CPU和主存資源的。隨著對(duì)CPU需求的增長(zhǎng),進(jìn)程以某種合理的平滑的方式慢了下來(lái)。這里給大家分享一些關(guān)于全面解析虛擬內(nèi)存,希望對(duì)大家能有所幫助。
虛擬內(nèi)存空間
1.保留區(qū)(受保護(hù)的地址)
保留區(qū)即為受保護(hù)的地址,大小為128M,位于虛擬地址空間的最低部分,未賦予物理地址。任何對(duì)它的引用都是非法的,用于捕捉使用空指針和小整型值指針引用內(nèi)存的異常情況。
它并不是一個(gè)單一的內(nèi)存區(qū)域,而是對(duì)地址空間中受到操作系統(tǒng)保護(hù)而禁止用戶進(jìn)程訪問(wèn)的地址區(qū)域的總稱。大多數(shù)操作系統(tǒng)中,極小的地址通常都是不允許訪問(wèn)的,如NULL。C語(yǔ)言將無(wú)效指針賦值為0也是出于這種考慮,因?yàn)?地址上正常情況下不會(huì)存放有效的可訪問(wèn)數(shù)據(jù)。。
2.代碼段
代碼段也稱正文段或文本段,通常用于存放程序執(zhí)行代碼(即CPU執(zhí)行的機(jī)器指令)。一般C語(yǔ)言執(zhí)行語(yǔ)句都編譯成機(jī)器代碼保存在代碼段。通常代碼段是可共享的,因此頻繁執(zhí)行的程序只需要在內(nèi)存中擁有一份拷貝即可。代碼段通常屬于只讀,以防止其他程序意外地修改其指令(對(duì)該段的寫操作將導(dǎo)致段錯(cuò)誤)。某些架構(gòu)也允許代碼段為可寫,即允許修改程序。
3.數(shù)據(jù)段(.data段)
數(shù)據(jù)段通常用于存放程序中已初始化的全局變量和靜態(tài)局部變量。數(shù)據(jù)段屬于靜態(tài)內(nèi)存分配(靜態(tài)存儲(chǔ)區(qū)),可讀可寫。由于全局變量未初始化時(shí),其默認(rèn)值為0,因此值為0的全局變量位于.bbs段(不位于數(shù)據(jù)段)。對(duì)于未初始化的局部變量,其值是不可預(yù)測(cè)的。注意:在代碼段和數(shù)據(jù)段之間還包括其它段:只讀數(shù)據(jù)段和符號(hào)段等。
4. .bbs段
該段用于存放未初始化的全局變量和靜態(tài)局部變量,包括值為0的全局變量。 數(shù)據(jù)段和.bbs段又稱為全局?jǐn)?shù)據(jù)區(qū),前者初始化,后者未初始化。
ELF段包括:代碼段、其它段(在.data段和.text段之間,包括只讀數(shù)據(jù)段和符號(hào)段等)、.data段(數(shù)據(jù)段)和.bbs段,都屬于可執(zhí)行程序部分。
5.堆空間
new( )和malloc( )函數(shù)分配的空間就屬于堆空間。
分配的堆內(nèi)存是經(jīng)過(guò)字節(jié)對(duì)齊的空間,以適合原子操作。堆管理器通過(guò)鏈表管理每個(gè)申請(qǐng)的內(nèi)存,由于堆申請(qǐng)和釋放是無(wú)序的,最終會(huì)產(chǎn)生內(nèi)存碎片。堆內(nèi)存一般由應(yīng)用程序分配釋放,回收的內(nèi)存可供重新使用。若程序員不釋放,程序結(jié)束時(shí)操作系統(tǒng)可能會(huì)自動(dòng)回收。
堆的末端由break指針標(biāo)識(shí),當(dāng)堆管理器需要更多內(nèi)存時(shí),可通過(guò)系統(tǒng)調(diào)用brk()和sbrk()來(lái)移動(dòng)break指針以擴(kuò)張堆,一般由系統(tǒng)自動(dòng)調(diào)用。
使用堆時(shí)經(jīng)常出現(xiàn)兩種問(wèn)題:1) 釋放或改寫仍在使用的內(nèi)存(“內(nèi)存破壞”);2)未釋放不再使用的內(nèi)存(“內(nèi)存泄漏”)。當(dāng)釋放次數(shù)少于申請(qǐng)次數(shù)時(shí),可能已造成內(nèi)存泄漏。泄漏的內(nèi)存往往比忘記釋放的數(shù)據(jù)結(jié)構(gòu)更大,因?yàn)樗峙涞膬?nèi)存通常會(huì)圓整為下個(gè)大于申請(qǐng)數(shù)量的2的冪次(如申請(qǐng)212B,會(huì)圓整為256B)。
6.內(nèi)存映射段(共享庫(kù))
內(nèi)核將硬盤文件的內(nèi)容直接映射到內(nèi)存, 任何應(yīng)用程序都可通過(guò)Linux的mmap()系統(tǒng)調(diào)用請(qǐng)求這種映射。內(nèi)存映射是一種方便高效的文件I/O方式, 因而被用于裝載動(dòng)態(tài)共享庫(kù)。如C標(biāo)準(zhǔn)庫(kù)函數(shù)(fread、fwrite、fopen等)和Linux系統(tǒng)I/O函數(shù),它們都是動(dòng)態(tài)庫(kù)函數(shù),其中C標(biāo)準(zhǔn)庫(kù)函數(shù)都被封裝在了/lib/libc.so庫(kù)文件中,都是二進(jìn)制文件。這些動(dòng)態(tài)庫(kù)函數(shù)都是與位置無(wú)關(guān)的代碼,即每次被加載進(jìn)入內(nèi)存映射區(qū)時(shí)的位置都是不一樣的,因此使用的是其本身的邏輯地址,經(jīng)過(guò)變換成線性地址(虛擬地址),然后再映射到內(nèi)存。而靜態(tài)庫(kù)不一樣,由于靜態(tài)庫(kù)被鏈接到可執(zhí)行文件中,因此其位于代碼段,每次在地址空間中的位置都是固定的。
7.??臻g
用于存放局部變量(非靜態(tài)局部變量,C語(yǔ)言稱為自動(dòng)變量),分配存儲(chǔ)空間時(shí)從上往下。
虛擬內(nèi)存實(shí)現(xiàn)方式
頁(yè)面和頁(yè)框
我們來(lái)打個(gè)比方,假設(shè)你現(xiàn)在有一臺(tái)32KB內(nèi)存的電腦,虛擬內(nèi)存是64KB。首先我們先將64KB的虛擬內(nèi)存切個(gè)片,一個(gè)片大小為4KB,所以總共切了16片。同時(shí),把32KB的物理內(nèi)存也按4KB的切片,總共切了8片。那么我們就稱虛擬內(nèi)存的一個(gè)片叫做頁(yè)面,物理內(nèi)存的一個(gè)片叫做頁(yè)框。
頁(yè)表
同學(xué)們可能已經(jīng)猜到了,沒(méi)錯(cuò),虛擬內(nèi)存和物理內(nèi)存之間是有一個(gè)映射關(guān)系的。這個(gè)映射該怎么實(shí)現(xiàn)呢,這就需要我們頁(yè)表的登場(chǎng)啦!頁(yè)表中維護(hù)著頁(yè)表和頁(yè)框的對(duì)應(yīng)關(guān)系。舉個(gè)栗子,一個(gè)地址為0x0010000000000100的16位地址。16位地址可拆分為兩部分,前4位和后12位。前4位對(duì)應(yīng)著16個(gè)虛擬頁(yè)表的號(hào)牌用于在頁(yè)表中尋找對(duì)應(yīng)的頁(yè)框號(hào),后12位用于頁(yè)內(nèi)偏址。0010即是2號(hào),我們?cè)陧?yè)表中查找2號(hào)選手對(duì)應(yīng)的頁(yè)框,假設(shè)是100。那么我們虛擬地址所對(duì)應(yīng)的物理地址即可得出,為100+之前的后12位頁(yè)內(nèi)偏移地址,即0x100000000000100。
不過(guò)畢竟頁(yè)面比頁(yè)框?yàn)?6:8,那么肯定會(huì)有一部分的頁(yè)面沒(méi)有所對(duì)應(yīng)的頁(yè)框,如果我們的虛擬地址就在這些頁(yè)面中我們?cè)撛趺崔k呢?
缺頁(yè)中斷
沒(méi)錯(cuò),如果我們的虛擬地址所在頁(yè)面沒(méi)有對(duì)應(yīng)的頁(yè)框,那么系統(tǒng)會(huì)產(chǎn)生一個(gè)缺頁(yè)中斷。缺頁(yè)中斷使CPU停下手頭的工作,轉(zhuǎn)而去尋找一個(gè)使用最少的一個(gè)頁(yè)框,將其寫入到磁盤中(如果頁(yè)框范圍內(nèi)地址的內(nèi)容有改變的話,沒(méi)有改變則不需要寫入磁盤)。然后修改將頁(yè)面指向該頁(yè)框,修改映射關(guān)系,至此缺頁(yè)中斷處理結(jié)束。CPU繼續(xù)執(zhí)行之前的工作。
TLB
到這里,虛擬內(nèi)存已經(jīng)可以完整的映射到物理內(nèi)存了,但還有一些問(wèn)題。那就是速度問(wèn)題。我們?cè)O(shè)想一下,如果把頁(yè)表存儲(chǔ)在進(jìn)程中,那么每次CPU都得進(jìn)入內(nèi)存中查詢,非常的影響速度。那我們?nèi)绻O(shè)置一個(gè)寄存器在CPU中,那速度不就很快了么?確實(shí)這樣CPU的訪問(wèn)速度會(huì)非常的快,但是每次的進(jìn)程切換,都會(huì)有新的頁(yè)表載入該寄存器中,同樣非常影響速度。那我們就沒(méi)有辦法了么?根據(jù)計(jì)算機(jī)科學(xué)家的統(tǒng)計(jì),其實(shí)有一些頁(yè)面映射是非常頻繁的,而剩余的映射則非常少,那么我們就可以將這些映射最頻繁的頁(yè)面放入CPU寄存器中,而這個(gè)CPU寄存器我們就叫他TLB。
虛擬內(nèi)存原理
內(nèi)存在計(jì)算機(jī)中的作用很大,電腦中所有運(yùn)行的程序都需要經(jīng)過(guò)內(nèi)存來(lái)執(zhí)行,如果執(zhí)行的程序很大或很多,就會(huì)導(dǎo)致內(nèi)存消耗殆盡。為了解決這個(gè)問(wèn)題,Windows中運(yùn)用了虛擬內(nèi)存技術(shù),即拿出一部分硬盤空間來(lái)充當(dāng)內(nèi)存使用,當(dāng)內(nèi)存占用完時(shí),電腦就會(huì)自動(dòng)調(diào)用硬盤來(lái)充當(dāng)內(nèi)存,以緩解內(nèi)存的緊張。舉一個(gè)例子來(lái)說(shuō),如果電腦只有128MB物理內(nèi)存的話,當(dāng)讀取一個(gè)容量為200MB的文件時(shí),就必須要用到比較大的虛擬內(nèi)存,文件被內(nèi)存讀取之后就會(huì)先儲(chǔ)存到虛擬內(nèi)存,等待內(nèi)存把文件全部?jī)?chǔ)存到虛擬內(nèi)存之后,跟著就會(huì)把虛擬內(nèi)里儲(chǔ)存的文件釋放到原來(lái)的安裝目錄里了。
當(dāng)系統(tǒng)運(yùn)行時(shí),先要將所需的指令和數(shù)據(jù)從外部存儲(chǔ)器(如硬盤、軟盤、光盤等)調(diào)入內(nèi)存中,CPU再?gòu)膬?nèi)存中讀取指令或數(shù)據(jù)進(jìn)行運(yùn)算,并將運(yùn)算結(jié)果存入內(nèi)存中,內(nèi)存所起的作用就像一個(gè)“二傳手”的作用。當(dāng)運(yùn)行一個(gè)程序需要大量數(shù)據(jù)、占用大量?jī)?nèi)存時(shí),內(nèi)存這個(gè)倉(cāng)庫(kù)就會(huì)被“塞滿”,而在這個(gè)“倉(cāng)庫(kù)”中總有一部分暫時(shí)不用的數(shù)據(jù)占據(jù)著有限的空間,所以要將這部分“惰性”的數(shù)據(jù)“請(qǐng)”出去,以騰出地方給“活性”數(shù)據(jù)使用。這時(shí)就需要新建另一個(gè)后備“倉(cāng)庫(kù)”去存放“惰性”數(shù)據(jù)。由于硬盤的空間很大,所以微軟Windows操作系統(tǒng)就將后備“倉(cāng)庫(kù)”的地址選在硬盤上,這個(gè)后備“倉(cāng)庫(kù)”就是虛擬內(nèi)存。在默認(rèn)情況下,虛擬內(nèi)存是以名為Pagefile.sys的交換文件保存在硬盤的系統(tǒng)分區(qū)中。
虛擬內(nèi)存相關(guān)文章:
★ 如何合理設(shè)置電腦虛擬內(nèi)存,提高電腦運(yùn)行速度
★ 提高內(nèi)存使用效能的幾種方法
★ 介紹幾個(gè)妙招加快內(nèi)存運(yùn)行速度
★ 全面釋放C盤被強(qiáng)行占用的空間
★ 讓你的電腦一點(diǎn)都不卡
★ 電腦系統(tǒng)資源不足及解決辦法
★ 電腦技巧
★ 電腦技巧
★ 電腦死機(jī)的常見原因
★ 關(guān)于電腦死機(jī)的原因及解決方法分享
本站部分文章來(lái)自網(wǎng)絡(luò)或用戶投稿。涉及到的言論觀點(diǎn)不代表本站立場(chǎng)。閱讀前請(qǐng)查看【免責(zé)聲明】發(fā)布者:天下,如若本篇文章侵犯了原著者的合法權(quán)益,可聯(lián)系我們進(jìn)行處理。本文鏈接:http://www.gdyuanyu.cn/dnxx/nczs/45571.html