您當前的位置:首頁 > 攝影

詳解linux虛擬記憶體原理

作者:由 飛翔的豬 發表于 攝影時間:2020-03-28

詳解linux虛擬記憶體原理

一、程式載入過程

詳解linux虛擬記憶體原理

我們程式是從磁碟中編碼的,程式碼執行的時候,首先載入至記憶體中,然後到暫存器中(

暫存器是存放各種給cpu計算用的地址、資料用的

),最後至CPU;

二、記憶體對映

Linux 核心給每個程序都提供了一個獨立的虛擬地址空間,並且這個地址空間是連續的,程序就可以很方便地訪問記憶體,也就是我們常說的虛擬記憶體虛擬記憶體。

根據地址範圍的不同,我們分為32位和64位,一般我們見的比較多的就是32位作業系統,這裡就都介紹一下;

虛擬記憶體被分為使用者空間和核心空間兩部分;這兩個其實在許可權上就有一定的區分了;當我們的

程序在使用者態的時候,只能訪問使用者空間

只有進入核心態,才能訪問核心空間;

我們看一下32位地址和64位地址空間的分佈:

詳解linux虛擬記憶體原理

這裡會有一種錯覺,我們每個程序都佔有了這麼多的空間,那麼多個程序怎麼辦?事實上並沒有那麼多的空間,其實這個本質是就是一種“自欺欺人”的做法,每個程序都以為自己佔據了全部的地址空間;其實只有在實際使用虛擬記憶體的時候,才會分配物理記憶體;

使用者空間是每個程序私有的;核心空間是每個程序共享的,不與任何使用者程序共享;

透過記憶體對映將

虛擬記憶體地址

對映到

物理記憶體地址

,對實際使用虛擬記憶體並分配的物理記憶體進行管理;

作用就是

:只會將某一程序此刻需要的記憶體大小對映到物理記憶體,其它暫時不需要的內容交換到硬碟儲存即可。當程序需要使用在硬碟中的內容或者需要動態申請記憶體時,

作業系統會利用缺頁操作,觸發一次記憶體對映

,將另外的物理記憶體對映進虛擬記憶體,供程式使用,這樣對於程序而言,則認為記憶體總是夠用的。

各個程序均擁有3G虛擬記憶體,那麼作業系統是如何做到各程序所使用的實際物理記憶體不會互相佔用呢?實際上,各個程序均有自己的記憶體對映表。任意一個時刻,在一個CPU上只有一個程序在執行。所以對於此CPU來講,在這一時刻,整個系統只存在一個4GB的虛擬地址空間,這個虛擬地址空間是面向此程序的。當程序發生切換的時候,虛擬地址空間也隨著切換。由此可以看出,每個程序都有自己的虛擬地址空間,只有此程序執行的時候,其虛擬地址空間才被執行它的CPU所知。在其它時刻,其虛擬地址空間對於CPU來說,是不可知的。所以儘管每個程序都可以有4 GB的虛擬地址空間,但在CPU眼中,只有一個虛擬地址空間存在。虛擬地址空間的變化,隨著程序切換而變化。

記憶體對映原理

詳解linux虛擬記憶體原理

虛擬記憶體對映到物理記憶體地址,核心為每一個程序維護了一張表,記錄了他們對應的對映關係;

而當程序訪問的虛擬地址在頁表中查不到時,系統會產生一個

缺頁異常

,進入核心空間分配物理記憶體、更新程序頁表,最後再返回使用者空間,恢復程序的執行。

Linux

採用了

四級頁表

來管理記憶體頁,多級頁表就是把記憶體分成區塊來管理,將原來的對映關係改成區塊索引和區塊內的偏移。由於虛擬記憶體空間通常只用了很少一部分,那麼,多級頁表就只儲存這些使用中的區塊,這樣就可以大大地減少頁表的項數。

三、虛擬記憶體空間分佈

虛擬地址空間

0~3G

用於使用者層 虛擬地址空間

3~4G

用於核心層

這個圖可能是我們見過最到的了

詳解linux虛擬記憶體原理

詳解linux虛擬記憶體原理

地址空間儲存的資料:

棧:儲存區域性變數、函式形參、自動變數。資料具有先進先出、後進後出的特 點;

堆:儲存由malloc、ralloc、calloc分配空間的變數。

BSS段:儲存未初始化或初始化為0的全域性變數和靜態區域性變數。

data段(資料段):儲存初始化不為0的全域性變數或者static修飾的變數。

程式碼段:儲存程式碼、可執行程式碼、字串字面值、只讀變數;

想了解學習更多C++後臺伺服器方面的知識,請關注: 微信公眾號:====

CPP後臺伺服器開發

====