想和你聊聊操作系統(tǒng)的內(nèi)存管理
“大家好,這里是公眾號:java小杰要加油,這周來分享一個操作系統(tǒng)的相關(guān)知識——內(nèi)存管理
話不多說,直接開車
物理地址 VS 虛擬地址
物理地址:邏輯上,我們可以把物理內(nèi)存看成一個大數(shù)組,其中每個字節(jié)都可以通過與之對應的地址進行訪問,這個地址就叫做物理地址
虛擬地址 :應用程序在運行時使用的地址
CPU翻譯虛擬地址的過程大概如圖所示

他們的包含關(guān)系如下:cpu包含MMU,MMU包含TLB
CPU TLB(轉(zhuǎn)址旁路緩存 Translation Lookaside Buffer):加速地址翻譯的過程 MMU(內(nèi)存管理單元 Memory Management Unit): 負責虛擬地址到物理地址的轉(zhuǎn)換
平常加載程序的順序是
操作系統(tǒng)把程序從磁盤加載到內(nèi)存中(程序一開始是在磁盤中存放的) CPU去執(zhí)行程序的第一條指令但是這個指令現(xiàn)在在物理內(nèi)存中 cpu取指令取的是該指令的虛擬地址,由MMU翻譯為物理地址 這個讀物理地址的請求將通過總線,傳送到相應的物理內(nèi)存中,然后物理內(nèi)存把該指令發(fā)送給CPU
分段
“MMU將虛擬地址翻譯為物理地址主要有兩種機制 :分段和分頁
分段機制
操作系統(tǒng)以“段”(一段連續(xù)的物理內(nèi)存)的形式管理/分配物理內(nèi)存 應用程序的虛擬地址空間由若干個大小不同的段組成:代碼段、數(shù)據(jù)段等等 當CPU訪問虛擬地址中的某一個段的時候,MMU會通過查詢段表來得到該段對應的物理地址

虛擬地址:
段號: 標志著該虛擬地址屬于整個虛擬地址空間中的哪一段 段內(nèi)地址(段內(nèi)偏移): 相對于該段起始地址的偏移量
“當 cpu 讀取指令時,發(fā)現(xiàn)指令的地址是虛擬地址,那么CPU中的MMU 首先判斷這個段號是否合法,如果合法, 則通過 段表基址寄存器 找到段表的位置,通過虛擬地址中的段號,找到該段的起始地址,再加上段內(nèi)地址(段內(nèi)偏移),就可以得到最終的物理地址
在分段機制下,虛擬內(nèi)存和物理內(nèi)存都劃分成了不同的段
分段缺點
在虛擬地址空間中,相鄰的段所對應的物理內(nèi)存空間可以不相鄰,操作系統(tǒng)能夠?qū)崿F(xiàn)物理內(nèi)存資源的離散分配,但是這種段式分配方式容易導致在物理內(nèi)存上出現(xiàn)外部碎片
圖中裝載不進來的就是外部碎片
分頁機制
基本思想: 將應用程序的虛擬地址空間劃分為連續(xù)的、等長的虛擬頁(4K) 物理地址也是劃分為連續(xù)的、等長的的物理頁 物理頁和虛擬頁頁長固定且相等
之所以這樣構(gòu)造是因為會使操作系統(tǒng)很方便的為每個應用程序構(gòu)造頁表,即虛擬頁和物理頁映射關(guān)系表
在分頁機制下,應用程序虛擬地址空間中的任意虛擬頁可以被映射到物理內(nèi)存中的任意物理頁上,可以避免外部碎片的問題
分頁機制下的虛擬地址也由兩部分組成:虛擬頁號: 頁內(nèi)偏移量:

翻譯的具體流程就是:
“
MMU首先解析虛擬地址中的虛擬頁號,檢查這個虛擬頁號是否合法,通過這個虛擬頁號取該應用程序的虛擬頁表中找到對應條目(頁表起始地址放在頁表基地址寄存器) 然后取出該條目中的物理頁號 最后用該物理頁號對應的物理起始地址加上虛擬地址中的頁內(nèi)偏移得到最終的物理地址
TLB
首先要說一下局部性原理
時間局部性: 如果執(zhí)行了程序中的某條指令,那么不久后這條指令很有可能再次執(zhí)行,如果某個數(shù)據(jù)被訪問過,不久后該數(shù)據(jù)很可能再次被訪問(因為程序中存在大量的循環(huán)) 空間局部性: 一旦程序訪問了某個存儲單元,在不久之后,其附近的存儲單元也很有可能會被訪問(因為很多數(shù)據(jù)在內(nèi)存中都是連續(xù)存放的)
所以,能不能弄一個緩存,緩存這些有可能會被經(jīng)常被訪問的數(shù)據(jù)呢,從而減少訪問頁表的次數(shù)呢?
“為了減少地址翻譯的訪問次數(shù),MMU引入TLB(轉(zhuǎn)址旁路緩存 Translation Lookaside Buffer)
TLB 硬件采用分層架構(gòu),分為L1、L2兩層。 LI又分為數(shù)據(jù)TLB和指令TLB,分別緩存數(shù)據(jù)和指令的地址翻譯 L2不區(qū)分數(shù)據(jù)和指令 TLB緩存了虛擬頁號和物理頁號的映射關(guān)系,類似map,key是虛擬頁號,value是物理頁號。 如果在TLB中找到則稱為TLB命中 沒有找到則稱之為TLB未命中

“有了TLB之后,查詢就變成了
1. MMU首先解析虛擬地址中的虛擬頁號,檢查這個虛擬頁號是否合法,如果合法
查TLB,如果命中則 直接取出物理初始地址,再加上頁內(nèi)偏移量得到最終物理地址,否則繼續(xù)查詢頁表 如果頁表中存在物理初始地址,則將此物理初始地址緩存到TLB中 通過這個虛擬頁號取該應用程序的虛擬頁表中找到對應條目(頁表起始地址放在頁表基地址寄存器)
然后取出該條目中的物理頁號 最后用該物理頁號對應的物理起始地址加上虛擬地址中的頁內(nèi)偏移得到最終的物理地址
多級頁表
如果頁表太大時怎么辦,頁表必須連續(xù)存放,會占用很多內(nèi)存,所以就把一個大表拆成很多小表
拆分后的訪問順序如圖所示

根據(jù)一級頁號查找到物理頁號,這個物理頁號里面裝的是二級頁表的地址,找到此地址后,在根據(jù)二級頁號 找到物理地址,此物理地址在加上頁內(nèi)偏移量則為最終的物理地址
換頁與缺頁異常
換頁
“虛擬內(nèi)存中的換頁:當物理內(nèi)存容量不夠的時候,操作系統(tǒng)應當把若干物理頁的內(nèi)容寫到磁盤這種大容量的地方,然后回收物理頁并繼續(xù)使用
舉例:有個應用程序A,A的虛擬頁K對應物理頁V,這個時候,操作系統(tǒng)想回收物理頁V,要怎么做呢?
操作系統(tǒng)把V寫到磁盤上 并且在A的頁表中除去虛擬頁K和物理頁V的映射,同時記錄物理頁V被換到磁盤上的對應的位置
以上這兩部被稱為物理頁V的換出
缺頁異常
“缺頁異常是換頁機制能夠工作的前提,當應用程序訪問已經(jīng)分配但是未映射至物理內(nèi)存的虛擬頁時,就會觸發(fā)缺頁異常
如何解決:通過換入 cpu會運行操作系統(tǒng)預先設置的缺頁異常處理函數(shù),該函數(shù)會找到一個空閑的物理頁, 將以前寫入到磁盤上的內(nèi)容重新加載到該空閑的物理頁 然后將虛擬地址和此物理地址映射起來
處理完這一切后,cpu回到發(fā)生缺頁異常的地方繼續(xù)運行

段頁式內(nèi)存管理
分段管理
優(yōu)點: 很方便的按照邏輯模塊實現(xiàn)信息的共享和保護 缺點: 容易產(chǎn)生外部碎片 分頁管理
優(yōu)點 內(nèi)存空間利用率高,不會產(chǎn)生外部碎片,只會有少量頁內(nèi)碎片 缺點: 不方便按照邏輯模塊實現(xiàn)信息的共享和保護 段頁式內(nèi)存管理
將地址空間按照程序自身的邏輯關(guān)系分為若干層,將各段分為大小相等的頁面 將物理內(nèi)存與虛擬內(nèi)存劃分為大小相等的一個個的內(nèi)存塊,系統(tǒng)以塊為單位為進程分配內(nèi)存 邏輯地址/虛擬地址(段號,頁號,頁內(nèi)偏移量) 
虛擬地址翻譯為物理地址的步驟變?yōu)?/p>
根據(jù)邏輯地址取出其中的段號,判斷這個段號是否正常 如果正常,則找到該段號對應的頁表初始地址 根據(jù)頁號是否正常,若正常則根據(jù)頁號找到物理初始地址,在加上頁內(nèi)偏移量則找到真正的物理地址

往期推薦

