作業系統概念總結筆記——第八章 記憶體管理
本章目標:
1、詳細討論記憶體硬體的組織方法;
2、討論各種記憶體管理技術,如分段、分頁;
8.1 背景介紹
快取記憶體: 由於CPU對暫存器的訪問速率快於對記憶體的訪問速率,導致在實際執行中,沒有資料完成正在進行的操作,CPU通常需要暫停(stall), 由於記憶體的頻繁訪問,這種暫停是難以接受的,所以增加快取記憶體,用於協調速度的差異。
程式空間: 要確保每個程序都有獨立的記憶體空間,因此需要確定程序可訪問的合法記憶體訪問,這裡使用兩個暫存器來實現著這種保護:基地址暫存器(最小的合法實體記憶體地址)、界限地址暫存器(地址範圍)。
地址繫結: 編譯器通常需要將源程式中的地址繫結到可重定位的地址, 連結程式或載入程式再將這些可重定位的地址繫結成絕對地址,每次繫結都是從一個地址空間到另一個地址空間的對映。
通常,將指令和資料繫結到記憶體地址有以下幾種情況:
編譯時繫結:事先知道程式在記憶體空間的位置,就可以在編譯時生成絕對程式碼,從該位置開始並向後擴充套件,如果後來開始地址發生變化,那麼就必須重新編譯程式碼。不同的人安排程式的位置可能衝突。
載入時繫結:如果在編譯時不知道程式在記憶體空間的位置,那麼編譯時必須生成可重定位程式碼(可以使地址平移的程式碼稱為可重定位程式碼,它通過載入過程中系統給定的實體地址,生成程式的實體地址),延遲到載入時繫結程式,稱為靜態地址重定位。
執行時繫結:如果程序在執行時可以從一個記憶體段轉移到另一個記憶體段,那麼繫結要延遲到執行時才進行,在每次CPU訪問記憶體時,進行地址的轉換,需要藉助某種物理裝置,稱為動態地址重定位。
靜態地址重定位:不需要硬體支援,不能移動程式碼,不能處理非連續程式碼;
動態地址重定位:需要重定位暫存器,重定位暫存器使用如下:
邏輯地址:CPU所產生的地址;
實體地址:記憶體單元使用的地址;
8.2 交換
交換(swap): 程序暫時從記憶體中交換到備份儲存上,當需要再次執行時調回記憶體; 這種交換策略被用於基於優先順序的排程演算法,如果有一個更高優先順序的程序需要服務,記憶體管理器可以交換出低優先順序的程序,以便於執行更高優先順序的程序,當高優先順序程序執行完畢後,低優先順序程序可以交換回記憶體以便繼續執行;
這種交換有時被稱為滾出(roll out),滾入(roll in);
通常,若程式使用編譯時繫結或載入時繫結,那麼交換後必須返回原來的地址空間; 若程式使用執行時繫結,則交換後可以移到不同的空間;
交換需要備份儲存,備份儲存通常使用快速磁碟,必須足夠大以便容納所有使用者的記憶體映象副本,也必須提供對這些記憶體映象的直接訪問; 假設使用者程序的大小為10MB,備份儲存是傳輸速度為40MBps,那麼10MB程序傳入或傳出的速度為250ms,假定平均定址時間是8ms,那麼交換時間為258ms,由於涉及換入和換出,總的交換時間為516ms;
8.3 連續記憶體分配
記憶體對映與保護:採用重定位暫存器和界限地址暫存器,進行保護;重地址暫存器含有最小的實體地址值,界限地址暫存器含有邏輯地址的範圍值; 進行對映時,記憶體管理單元要求邏輯地址必須小於界限地址暫存器的值,並把邏輯地址與重地址暫存器的值相加,映射出實體地址的值;
多分割槽方法: 最簡單的記憶體分配方法是將記憶體分為多個固定大小的分割槽(partition),每個分割槽容納一個程序,多道程式的程度也會受到分割槽數的限制,當一個分割槽空閒時,就從輸入佇列中選擇一個程序調入空閒分割槽。
動態儲存分配的常用方法:
首次適應(first-fit):分配第一個足夠大的記憶體塊給程序使用,一旦找到足夠大的記憶體塊,就立即停止掃描;
最佳適應(best-fit): 分配最小的足夠大的記憶體塊,除非列表按大小排列,那麼要求必須掃描整個列表;
最差適應(worst-fit): 分配最大的記憶體塊,除非列表按大小排列,那麼要求必須掃描整個列表;
比較這三種方法,空間利用率方面:首次適應和最佳適應均好於最差適應; 執行時間方面:首次適應優於最佳適應優於最差適應, 但是,首次適應和最佳適應都會產生外部碎片問題;
外部碎片:還沒有分配出去,但是由於太小而無法使用的記憶體;
內部碎片:已經分配給程序,但是無法使用的記憶體;
在首次適應和最佳適應的執行過程中,隨著程序的不斷裝入和移出,就會出現外部碎片問題;
緊縮(compaction):緊縮是一種解決外部碎片的問題,通過移動記憶體內容,使得所有空閒的記憶體空間整合到一起; 緊縮僅在繫結方式為執行時繫結才可以執行;若使用編譯時繫結和裝入時繫結,那麼就不能對程序進行移動; 最簡單的緊縮方法是將所有的程序移到記憶體的一端,而將所有空閒記憶體塊移到記憶體的另一端,這種方案開銷較大;
另一種解決外部碎片的方法是允許實體地址空間非連續,使用分頁、分段技術;
8.4 分頁
實現分頁的基本方法: 將實體記憶體分為固定大小的塊,稱為幀(frame),將邏輯記憶體分為同樣大小的塊,稱為頁(page),當需要執行程序時,將程序頁從備份儲存調入到可用的記憶體幀中; 幀的大小和頁的大小相同;
地址生成: CPU產生的每個地址分為兩個部分:頁號(p),頁偏移(d), 頁號作為頁表中的索引,從頁表中提取出每頁所在實體地址的基地址,這個基地址和之前的頁偏移組合,形成實體地址; 頁的大小通常為2的冪,由頁的偏移量決定,分頁操作如下:
分頁也是一種動態重定位,每個邏輯地址由分頁硬體繫結為一定的實體地址; 採用分頁技術不會產生外部碎片,每個幀都可以分配給需要它的程序,但會產生內部碎片:分配是以幀為單位進行的,如果程序所要求的記憶體並不是幀的整數倍,那麼最後一個幀可能用不完,這就會產生內部碎片;
當程序需要執行時,首先檢測該程序的大小,程序的每頁都需要一幀,如果程序需要n頁,那麼記憶體中應該有n個幀,如果有,就可以分配給新程序;
幀表: 作業系統在管理實體記憶體的過程中,需要知道哪些幀已被佔用,哪些幀可用,總共有多少幀,等等; 這些資訊被儲存在被稱為幀表的資料結構中;
保護: 在分頁環境下,記憶體保護是通過與每一幀相關聯的保護位來實現的,這些保護位存在於頁表中,可以用一個位來定義一個頁是可讀還是可寫;用另一個位作為有效-無效位,當該位有效,表示相關的頁在程序的邏輯地址空間內,無效,則表示不在邏輯地址空間內;
共享:分頁的優點在於可以共享公共程式碼,實現方式是在每個程序的頁表中新增共享的資料頁,如圖,程序P1,P2,P3共享了ed1,ed2,ed3;
頁表的常用技術: 層次頁表、雜湊頁表、反向頁表;
層次頁表:現代計算機系統支援很大的邏輯地址空間,導致頁表本身可以非常大,顯然不利於在記憶體中連續分配一個大的頁表,一個簡單的方法是將頁表劃分為更小的部分; 一種方法是兩級分頁演算法:
雜湊頁表: 處理超過32位地址空間的常用方法是使用雜湊頁表,以虛擬頁碼作為雜湊值,然後對域內元素進行匹配,得到相應的幀號,形成實體地址:
反向頁表:
8.5 分段
分段是支援使用者視角的記憶體管理方案,類似於在寫程式時,人們會認為程式是由主程式加上方法、過程、函式所構成,分段把邏輯地址空間視作一組段構成的,每個段都有名稱和長度,使用者通過段名稱和段內偏移指定地址(在分頁中,使用者只提供一個地址,該地址通過硬體被劃分為頁碼和偏移量);
例如,C編譯器可能建立如下段:
1、程式碼
2、全域性變數
3、堆
4、每個執行緒的棧
5、標準的C庫函式
段表: 用於將二維的使用者定義地址對映為一維實體地址,段表的每個條目都有段基地址和段界限,段基地址存放該段在記憶體的開始實體地址,而段界限存放該段的長度,段表的硬體實現如下:
分段例項:
以段0為例,段基地址和段界限表示它的起始地址是1400,範圍是1000,所以實際的實體記憶體範圍是1400-2400;