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

記憶體管理:詳解虛擬地址空間-MMU

作者:由 玩轉Linux核心 發表于 攝影時間:2021-12-30

虛擬記憶體

虛擬記憶體就是在你電腦的物理記憶體不夠用時把一部分硬碟空間作為記憶體來使用,這部分硬碟空間就叫作虛擬記憶體。

硬碟傳輸的速度要比記憶體傳輸速度慢得多,所以虛擬記憶體比物理記憶體的效率要慢得多。

斷電後資料丟失。

虛擬地址空間

虛擬地址空間是一個非常抽象的概念,先根據字面意思進行解釋:

它可以用來載入程式資料(資料可能被載入到物理記憶體上,空間不夠就載入到虛擬記憶體中)

它對應著一段連續的記憶體地址,起始位置為 0。

之所以說虛擬是因為這個起始的 0 地址是被虛擬出來的, 不是物理記憶體的 0 地址。

虛擬地址空間的大小也由作業系統決定,32位的作業系統虛擬地址空間的大小為 2^32 位元組,也就是 4G,64 系統的作業系統虛擬地址空間大小為 2^64 位元組,這是一個非常大的數,感興趣的可以自己計算一下。

關於虛擬4G記憶體的描述和解析:

一個程序用到的虛擬地址是由記憶體區域表來管理的,實際用不了4G。而用到的記憶體區域,會透過頁表對映到物理記憶體。

所以每個程序都可以使用同樣的虛擬記憶體地址而不衝突,因為它們的物理地址實際上是不同的。核心用的是3G以上的1G虛擬記憶體地址,其中896M是直接對映到物理地址的,128M按需對映896M以上的所謂高位記憶體。各程序使用的是同一個核心。

首先要分清“可以定址”和“實際使用”的區別。

其實我們講的每個程序都有4G虛擬地址空間,講的都是“可以定址”4G,意思是虛擬地址的0-3G對於一個程序的使用者態和核心態來說是可以訪問的,而3-4G是隻有程序的核心態可以訪問的。並不是說這個程序會用滿這些空間。

其次,所謂“獨立擁有的虛擬地址”是指對於每一個程序,都可以訪問自己的0-4G的虛擬地址。虛擬地址是“虛擬”的,需要轉化為“真實”的物理地址。

好比你有你的地址簿,我有我的地址簿。你和我的地址簿都有1、2、3、4頁,但是每頁裡面的實際內容是不一樣的,我的地址簿第1頁寫著3你的地址簿第1頁寫著4,對於你、我自己來說都是用第1頁(虛擬),實際上用的分別是第3、4頁(物理),不衝突。

核心用的896M虛擬地址是直接對映的,意思是隻要把虛擬地址減去一個偏移量(3G)就等於物理地址。同樣,這裡指的還是定址,實際使用前還是要分配記憶體。而且896M只是個最大值。如果物理記憶體小,核心能使用(分配)的可用記憶體也小。

程序的虛擬地址空間分為使用者區(03G)和核心區(34G), 其中核心區是受保護的, 使用者是不能夠對其進行讀寫操作的;

核心區對於所有程序是共享的;系統中所有程序對應的虛擬地址空間的核心區都會對映到同一塊物理記憶體上(系統核心只有一個)。

記憶體管理:詳解虛擬地址空間-MMU

虛擬地址空間中使用者區地址範圍是 0~3G,裡邊分為多個區塊:

保留區

: 位於虛擬地址空間的最底部,未賦予物理地址。任何對它的引用都是非法的,程式中的空指標(NULL)指向的就是這塊記憶體地址。

.text段

: 程式碼段也稱正文段或文字段,通常用於存放程式的執行程式碼 (即 CPU 執行的機器指令),程式碼段一般情況下是隻讀的,這是對執行程式碼的一種保護機制。

.data段

: 資料段通常用於存放程式中已初始化且初值不為 0 的全域性變數和靜態變數。資料段屬於靜態記憶體分配 (靜態儲存區),可讀可寫。

bss段

: 未初始化以及初始為 0 的全域性變數和靜態變數,作業系統會將這些未初始化的變數初始化為 0

堆(heap)

:用於存放程序執行時動態分配的記憶體。

堆中內容是匿名的,不能按名字直接訪問,只能透過指標間接訪問。

堆向高地址擴充套件 (即 “向上生長”),是不連續的記憶體區域。這是由於系統用連結串列來儲存空閒記憶體地址,自然不連續,而連結串列從低地址向高地址遍歷。

記憶體對映區(mmap)

:作為記憶體對映區載入磁碟檔案,或者載入程式運作過程中需要呼叫的動態庫。

棧(stack)

: 儲存函式內部宣告的非靜態區域性變數,函式引數,函式返回地址等資訊,棧記憶體由編譯器自動分配釋放。棧和堆相反地址 “向下生長”,分配的記憶體是連續的。

命令列引數

:儲存程序執行的時候傳遞給 main() 函式的引數,argc,argv [],env[]

環境變數

: 儲存和進行相關的環境變數,比如:工作路徑,程序所有者等資訊

記憶體管理單元MMU

MMU位於CPU內,作用:

程式中使用的地址均是虛擬記憶體地址,程序中的資料是如何進入到物理記憶體中的呢?

MMU完成虛擬記憶體到物理記憶體的對映,即虛擬地址對映為物理地址;

流水線中預取指令取到的地址是虛擬地址,需要MMU轉換以及設定訪問許可權

MMU採用分頁機制(即按頁來劃分物理記憶體)

用MMU的是

:Windows、MacOS、Linux、Android;

不用MMU的是

:FreeRTOS、VxWorks、UCOS……

與此相對應的:CPU也可以分成兩類,帶MMU的、不帶MMU的。

帶MMU的是

:Cortex-A系列、ARM9、ARM11系列;

不帶MMU的是

:Cortex-M系列……(STM32是M系列,沒有MMU,不能執行Linux,只能執行一些UCOS、FreeRTOS等等)。

虛擬地址和物理地址的對映關係儲存在頁表中,而現在頁表又是分級的

【文章福利

】小編推薦自己的Linux核心技術交流群:【

865977150

】整理了一些個人覺得比較好的學習書籍、影片資料共享在群檔案裡面,有需要的可以自行新增哦!!!

記憶體管理:詳解虛擬地址空間-MMU

核心學習網站:

頁表

實現從頁號到物理塊號的地址對映。

邏輯地址轉換成物理地址的過程是:用頁號p去檢索頁表,從頁表中得到該頁的物理塊號,把它裝入物理地址暫存器中。同時,將頁內地址d直接送入物理地址暫存器地塊內地址欄位中。這樣,物理地址暫存器中的內容就是由二者拼接成的實際訪問記憶體的地址,從而完成了從邏輯地址到物理地址的轉換。

TLB快表

TLB是MMU中的一塊快取記憶體,也是一種Cache。

TLB就是頁表的Cache,其中儲存了當前最可能被訪問到的頁表項,其內容是部分頁表項的一個副本。只有在TLB無法完成地址翻譯任務時,才會到記憶體中查詢頁表,這樣就減少了頁表查詢導致的處理器效能下降。

如果沒有TLB,則每次取資料都需要兩次訪問記憶體,即查頁表獲得物理地址和取資料.

虛擬地址空間以

為單位進行劃分,而相應的物理地址空間也被劃分,其使用的單位稱為

頁幀

,頁幀和頁必須保持相同,因為

記憶體與外部儲存器之間的傳輸是以頁為單位進行傳輸的

。例如,MMU可以透過一個對映項將VA的一頁0xb70010000xb7001fff對映到PA的一頁0x20000x2fff,如果CPU執行單元要訪問虛擬地址0xb7001008,則實際訪問到的物理地址是0x2008。

虛擬記憶體的哪個頁面對映到物理記憶體的哪個頁幀是透過

頁表(Page Table)來描述的,頁表儲存在物理記憶體中

MMU會查詢頁表來確定一個VA應該對映到什麼PA。

記憶體訪問級別的設定和修改(記憶體保護)

,在完成對映的同時,會設定CPU訪問該段記憶體的訪問級別(3,2,1,0 Linux只有使用者空間3,核心空間0),

如圖:

ro表示read only

0和3表示訪問級別

程式運行了兩次,產生兩個獨立的程序,因此虛擬地址空間不一樣

兩個程序共用一個核心區,對映一份(圖中也要透過MMU對映,懶得話而已)即可,其中

兩個程序的PCB不一樣

使用者區需要單獨對映

記憶體管理:詳解虛擬地址空間-MMU

MMU執行過程

OS和MMU是這樣配合的:

作業系統在初始化或分配、釋放記憶體時會執行一些指令在物理記憶體中填寫頁表,然後用指令設定MMU,告訴MMU頁表在物理記憶體中的什麼位置。

設定好之後,CPU每次執行訪問記憶體的指令都會自動引發MMU做查表和地址轉換操作,地址轉換操作由硬體自動完成,不需要用指令控制MMU去做。

我們在程式中使用的變數和函式都有各自的地址,在程式被編譯後,這些地址就成了指令中的地址,指令中的地址就成了CPU執行單元發出的記憶體地址,所以在啟用MMU的情況下, 程式中使用的地址均是

虛擬記憶體地址

,都會引發MMU進行查表和地址轉換操作。(注意理解這句話)

記憶體保護機制

中斷和異常

中斷由外部裝置產生,而 異常由CPU內部產生的

中斷產生與CPU當前執行的指令無關,而異常是由於當前執行的指令出現問題導致的g

處理器一般有

使用者模式(User Mode)和特權模式(privileged Mode)之分。作業系統可以在頁表中設定每個頁表訪問許可權,有些頁表不可以訪問,有些頁表只能在特權模式下訪問,有些頁表在使用者模式和特權模式下都可以訪問,同時,訪問許可權又分為可讀

可寫

可執行

三種。這樣設定之後,當CPU要訪問一個VA(Virtual Address)時,

MMU

會檢查CPU當前處於使用者模式還是特權模式,訪問記憶體的目的是讀資料、寫資料還是取指令執行,

如果與作業系統設定的許可權相符,則允許訪問,把VA轉換成PA,否則不允許執行,產生異常(Exception)

在正常情況下處理器在使用者模式執行使用者程式,在中斷或異常情況下處理器切換到特權模式執行核心程式,處理完中斷或異常之後再返回使用者模式繼續執行使用者程式。

段錯誤

我們已經遇到過很多次了,它是這樣產生的:

使用者程式要訪問的一個虛擬機器地址,經MMU檢查無權訪問。

MMU產生一個異常,CPU從使用者模式切換到特權模式,跳轉到核心程式碼中執行異常服務程式。

核心把這個異常解釋為段錯誤,把引發異常的程序終止掉。

使用者空間與核心通訊方式有哪些?

1)系統呼叫。使用者空間程序透過系統呼叫進入核心空間,訪問指定的核心空間資料;

2)共享對映區mmap。在程式碼中呼叫介面,實現核心空間與使用者空間的地址對映,在實時性要求很高的專案中為首選,省去複製資料的時間等資源,但缺點是不好控制;

3)驅動程式。使用者空間程序可以使用封裝後的系統呼叫介面訪問驅動裝置節點,以和執行在核心空間的驅動程式通訊;

4)copy_to_user()、copy_from_user(),是在驅動程式中呼叫介面,實現使用者空間與核心空間的資料複製操作,應用於實時性要求不高的專案中。

記憶體管理:詳解虛擬地址空間-MMU

標簽: 記憶體  MMU  虛擬地址  地址  頁表