linux虛擬內(nèi)存和物理內(nèi)存

虛擬內(nèi)存的由來

為什么會出現(xiàn)虛擬內(nèi)存呢?這就要從最初的操作系統(tǒng)來說起了,最初的操作系統(tǒng)并沒有現(xiàn)在那么完善,剛開始的時候,程序是直接裝載到物理內(nèi)存中的。這就導(dǎo)致了下面的一些問題:

  1. 程序編寫困難。
  2. 修改內(nèi)存數(shù)據(jù)導(dǎo)致程序崩潰。

先說問題1、為什么會導(dǎo)致程序編寫困難呢?因為,操作系統(tǒng)是同時運行好多程序的,編寫的程序是直接操作物理內(nèi)存的,編寫的時候就要考慮,自己的程序操作的內(nèi)存地址,是否已經(jīng)被其他程序占用了,如果被占用了的話,就要重新編寫程序,重新安排程序的操作地址。

再看問題2。因為是直接操作物理內(nèi)存,這就意味著一個程序可以操作內(nèi)存中的所有地址,如果有惡意程序修改了其他程序在用的地址中的數(shù)據(jù),這就可能導(dǎo)致其他程序崩潰。

虛擬內(nèi)存概念的出現(xiàn)就解決了上面的問題,虛擬內(nèi)存的概念出現(xiàn)后,程序的編寫就不再直接操作物理內(nèi)存了,對每個程序來說,它們就相當于擁有了所有的內(nèi)存空間,可以隨意操作,就不用擔(dān)心自己操作的內(nèi)存地址被其他程序占用的問題了。同時,因為程序操作的是虛擬內(nèi)存地址,這樣就不會出現(xiàn)因為修改了其他應(yīng)用程序內(nèi)存地址中的數(shù)據(jù)而導(dǎo)致其他應(yīng)用程序崩潰的問題了。

這時,你可能會問,CPU都是操作物理內(nèi)存的,這虛擬內(nèi)存怎么和物理內(nèi)存對應(yīng)呢?問題很好,下文會給你答案。

物理內(nèi)存和虛擬內(nèi)存

這里有必要說下物理內(nèi)存和虛擬內(nèi)存的概念,可能有的讀者分的不太清楚。

物理內(nèi)存: 真實的內(nèi)存,就是我們常說的那個4G、8G、16G的內(nèi)存條。
虛擬內(nèi)存: 是一個概念,并不是實際的內(nèi)存,對于4G內(nèi)存的Linux系統(tǒng)來說,虛擬內(nèi)存也為4G,其中1G為系統(tǒng)的內(nèi)存,剩下的3G為應(yīng)用程序的內(nèi)存。

image.png

解讀一下這張圖,就是有1G虛擬內(nèi)存是編寫的應(yīng)用程序操作不到的,應(yīng)用程序最多只能操作3G的虛擬內(nèi)存空間。

虛擬內(nèi)存和物理內(nèi)存的對應(yīng)關(guān)系

有計算機基礎(chǔ)的人應(yīng)該都知道,計算機的CPU操作的是物理內(nèi)存的地址,而現(xiàn)在編寫的程序操作的都是虛擬內(nèi)存地址,那么虛擬內(nèi)存怎樣和物理內(nèi)存對應(yīng)起來的呢?這就涉及到一些操作系統(tǒng)的知識了,虛擬內(nèi)存和物理內(nèi)存都有分頁的概念,一般一頁是4096個字節(jié),現(xiàn)在的操作系統(tǒng)虛擬地址和物理地址建立對應(yīng)關(guān)系采用的是頁映射的方式。

頁映射是虛擬存儲機制的一部分,它隨著虛擬存儲的發(fā)明而誕生。頁映射不是一下子就把程序的所有數(shù)據(jù)和指令都裝入內(nèi)存,而是將內(nèi)存和所有磁盤中的數(shù)據(jù)和指令按照“頁(Page)”為單位劃分成若干個頁,以后所有的裝載和操作的單位就是頁。以目前的情況,硬件規(guī)定的頁的大小有4 096字節(jié)、8 192字節(jié)、2 MB、4 MB等,最常見的Intel IA32處理器一般都使用4 096字節(jié)的頁,那么512 MB的物理內(nèi)存就擁有512 * 1024 * 1024 / 4 096 = 131 072個頁。

假設(shè)我們的32位機器有16 KB的內(nèi)存,每個頁大小為4 096字節(jié),則共有4個頁,


image.png

假設(shè)程序所有的指令和數(shù)據(jù)總和為32 KB,那么程序總共被分為8個頁。我們將它們編號為P0~P7。很明顯,16 KB的內(nèi)存無法同時將32 KB的程序裝入,那么我們將按照動態(tài)裝入的原理來進行整個裝入過程。如果程序剛開始執(zhí)行時的入口地址在P0,這時裝載管理器(我們假設(shè)裝載過程由一個叫裝載管理器的家伙來控制,就像覆蓋管理器一樣)發(fā)現(xiàn)程序的P0不在內(nèi)存中,于是將內(nèi)存F0分配給P0,并且將P0的內(nèi)容裝入F0;運行一段時間以后,程序需要用到P5,于是裝載管理器將P5裝入F1;就這樣,當程序用到P3和P6的時候,它們分別被裝入到了F2和F3,它們的映射關(guān)系如圖所示。

擴展

可能上面的內(nèi)容你還意猶未盡,那就再來簡單的描述一下,Linux是怎樣裝載可執(zhí)行程序的.首先,操作系統(tǒng)是會為一個可執(zhí)行程序分配一個進程的,然后裝載相應(yīng)的可執(zhí)行文件并執(zhí)行。當有虛擬內(nèi)存存在的情況下,上面的過程就要做三件事:

創(chuàng)建一個獨立的虛擬地址空間。
讀取可執(zhí)行文件頭,并建立可執(zhí)行文件與虛擬空間的映射。
將CPU的指令寄存器設(shè)置成可執(zhí)行文件的入口地址,啟動運行。

首先是創(chuàng)建虛擬地址空間。創(chuàng)建一個虛擬空間實際上并不是創(chuàng)建空間而是創(chuàng)建映射函數(shù)所需要的相應(yīng)的數(shù)據(jù)結(jié)構(gòu)。

讀取可執(zhí)行文件頭,并且建立虛擬空間與可執(zhí)行文件的映射關(guān)系。為什么要建立映射關(guān)系呢?因為,當程序執(zhí)行發(fā)生頁錯誤時,操作系統(tǒng)將從物理內(nèi)存中分配一個物理頁,然后將該“缺頁”從磁盤中讀取到內(nèi)存中,再設(shè)置缺頁的虛擬頁和物理頁的映射關(guān)系,這樣程序才得以正常運行。但是很明顯的一點是,當操作系統(tǒng)捕獲到缺頁錯誤時,它應(yīng)知道程序當前所需要的頁在可執(zhí)行文件中的哪一個位置。這就是虛擬空間與可執(zhí)行文件之間的映射關(guān)系。

再來看第3步,其實仔細思考第三步是會發(fā)現(xiàn)一些問題的,這里的可執(zhí)行文件的入口地址是虛擬內(nèi)存地址,那么就可能存在兩個可執(zhí)行程序的虛擬入口地址相同的問題,這個問題怎么解決呢?這時一個叫做“內(nèi)存管理單元(Memory Management Unit)”簡稱“MMU”的硬件就誕生了,它的作用之一就是地址翻譯,將虛擬地址翻譯成物理地址,可以看下圖,加深理解

image.png

簡單總結(jié)一下這部分的內(nèi)容,當操作系統(tǒng)裝載一個可執(zhí)行程序時,會首先創(chuàng)建虛擬地址空間,這個地址空間實際上就是一個數(shù)據(jù)結(jié)構(gòu);然后建立可執(zhí)行文件與虛擬地址的映射,映射的作用就是知道虛擬空間對應(yīng)可執(zhí)行文件的哪個位置;最后就是將CPU的指令寄存器設(shè)置成可執(zhí)行文件的入口地址,開始執(zhí)行程序,程序開始執(zhí)行的時候是會到入口地址那里找數(shù)據(jù)或程序執(zhí)行,如果入口地址沒有程序或數(shù)據(jù),就會產(chǎn)生缺頁中斷,然后將虛擬地址對應(yīng)可執(zhí)行文件中的部分裝載到物理內(nèi)存中,再將這塊物理內(nèi)存和虛擬內(nèi)存建立映射。

操作系統(tǒng)有虛擬內(nèi)存與物理內(nèi)存的概念。在很久以前,還沒有虛擬內(nèi)存概念的時候,程序?qū)ぶ酚玫亩际俏锢淼刂贰3绦蚰軐ぶ返姆秶怯邢薜?,這取決于CPU的地址線條數(shù)。比如在32位平臺下,尋址的范圍是2^32也就是4G。并且這是固定的,如果沒有虛擬內(nèi)存,且每次開啟一個進程都給4G的物理內(nèi)存,就可能會出現(xiàn)很多問題:

  • 因為我的物理內(nèi)存時有限的,當有多個進程要執(zhí)行的時候,都要給4G內(nèi)存,很顯然你內(nèi)存小一點,這很快就分配完了,于是沒有得到分配資源的進程就只能等待。當一個進程執(zhí)行完了以后,再將等待的進程裝入內(nèi)存。這種頻繁的裝入內(nèi)存的操作是很沒效率的

  • 由于指令都是直接訪問物理內(nèi)存的,那么我這個進程就可以修改其他進程的數(shù)據(jù),甚至?xí)薷膬?nèi)核地址空間的數(shù)據(jù),這是我們不想看到的

  • 由于指令都是直接訪問物理內(nèi)存的,那么我這個進程就可以修改其他進程的數(shù)據(jù),甚至?xí)薷膬?nèi)核地址空間的數(shù)據(jù),這是我們不想看到的

一個進程運行時都會得到4G的虛擬內(nèi)存。這個虛擬內(nèi)存你可以認為,每個進程都認為自己擁有4G的空間,這只是每個進程認為的,但是實際上,在虛擬內(nèi)存對應(yīng)的物理內(nèi)存上,可能只對應(yīng)的一點點的物理內(nèi)存,實際用了多少內(nèi)存,就會對應(yīng)多少物理內(nèi)存。

進程得到的這4G虛擬內(nèi)存是一個連續(xù)的地址空間(這也只是進程認為),而實際上,它通常是被分隔成多個物理內(nèi)存碎片,還有一部分存儲在外部磁盤存儲器上,在需要時進行數(shù)據(jù)交換。

進程開始要訪問一個地址,它可能會經(jīng)歷下面的過程

  1. 每次我要訪問地址空間上的某一個地址,都需要把地址翻譯為實際物理內(nèi)存地址
  2. 所有進程共享這整一塊物理內(nèi)存,每個進程只把自己目前需要的虛擬地址空間映射到物理內(nèi)存上
  3. 進程需要知道哪些地址空間上的數(shù)據(jù)在物理內(nèi)存上,哪些不在(可能這部分存儲在磁盤上),還有在物理內(nèi)存上的哪里,這就需要通過頁表來記錄
  4. 頁表的每一個表項分兩部分,第一部分記錄此頁是否在物理內(nèi)存上,第二部分記錄物理內(nèi)存頁的地址(如果在的話)
  5. 當進程訪問某個虛擬地址的時候,就會先去看頁表,如果發(fā)現(xiàn)對應(yīng)的數(shù)據(jù)不在物理內(nèi)存上,就會發(fā)生缺頁異常
  6. / 缺頁異常的處理過程,操作系統(tǒng)立即阻塞該進程,并將硬盤里對應(yīng)的頁換入內(nèi)存,然后使該進程就緒,如果內(nèi)存已經(jīng)滿了,沒有空地方了,那就找一個頁覆蓋,至于具體覆蓋的哪個頁,就需要看操作系統(tǒng)的頁面置換算法是怎么設(shè)計的了。
image.png

頁表的工作原理如下圖

image.png

1/. 我們的cpu想訪問虛擬地址所在的虛擬頁(VP3),根據(jù)頁表,找出頁表中第三條的值.判斷有效位。 如果有效位為1,DRMA緩存命中,根據(jù)物理頁號,找到物理頁當中的內(nèi)容,返回。

  1. 若有效位為0,參數(shù)缺頁異常,調(diào)用內(nèi)核缺頁異常處理程序。內(nèi)核通過頁面置換算法選擇一個頁面作為被覆蓋的頁面,將該頁的內(nèi)容刷新到磁盤空間當中。然后把VP3映射的磁盤文件緩存到該物理頁上面。然后頁表中第三條,有效位變成1,第二部分存儲上了可以對應(yīng)物理內(nèi)存頁的地址的內(nèi)容。
  2. 缺頁異常處理完畢后,返回中斷前的指令,重新執(zhí)行,此時緩存命中,執(zhí)行1。
  3. 將找到的內(nèi)容映射到告訴緩存當中,CPU從告訴緩存中獲取該值,結(jié)束。
再來總結(jié)一下虛擬內(nèi)存是怎么工作的

當每個進程創(chuàng)建的時候,內(nèi)核會為進程分配4G的虛擬內(nèi)存,當進程還沒有開始運行時,這只是一個內(nèi)存布局。實際上并不立即就把虛擬內(nèi)存對應(yīng)位置的程序數(shù)據(jù)和代碼(比如.text .data段)拷貝到物理內(nèi)存中,只是建立好虛擬內(nèi)存和磁盤文件之間的映射就好(叫做存儲器映射)。這個時候數(shù)據(jù)和代碼還是在磁盤上的。當運行到對應(yīng)的程序時,進程去尋找頁表,發(fā)現(xiàn)頁表中地址沒有存放在物理內(nèi)存上,而是在磁盤上,于是發(fā)生缺頁異常,于是將磁盤上的數(shù)據(jù)拷貝到物理內(nèi)存中。

另外在進程運行過程中,要通過malloc來動態(tài)分配內(nèi)存時,也只是分配了虛擬內(nèi)存,即為這塊虛擬內(nèi)存對應(yīng)的頁表項做相應(yīng)設(shè)置,當進程真正訪問到此數(shù)據(jù)時,才引發(fā)缺頁異常。

利用虛擬內(nèi)存機制的優(yōu)點
  1. 既然每個進程的內(nèi)存空間都是一致而且固定的(32位平臺下都是4G),所以鏈接器在鏈接可執(zhí)行文件時,可以設(shè)定內(nèi)存地址,而不用去管這些數(shù)據(jù)最終實際內(nèi)存地址,這交給內(nèi)核來完成映射關(guān)系
  2. 當不同的進程使用同一段代碼時,比如庫文件的代碼,在物理內(nèi)存中可以只存儲一份這樣的代碼,不同進程只要將自己的虛擬內(nèi)存映射過去就好了,這樣可以節(jié)省物理內(nèi)存
  3. 在程序需要分配連續(xù)空間的時候,只需要在虛擬內(nèi)存分配連續(xù)空間,而不需要物理內(nèi)存時連續(xù)的,實際上,往往物理內(nèi)存都是斷斷續(xù)續(xù)的內(nèi)存碎片。這樣就可以有效地利用我們的物理內(nèi)存
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
【社區(qū)內(nèi)容提示】社區(qū)部分內(nèi)容疑似由AI輔助生成,瀏覽時請結(jié)合常識與多方信息審慎甄別。
平臺聲明:文章內(nèi)容(如有圖片或視頻亦包括在內(nèi))由作者上傳并發(fā)布,文章內(nèi)容僅代表作者本人觀點,簡書系信息發(fā)布平臺,僅提供信息存儲服務(wù)。

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