分配回收
內存中哪裏可以放?怎麼選?怎麼收回結束的進程?
傳統的存儲管理方式:
連續分配
分配區域內沒有被進程使用的部分,稱內部碎片
分配區域外沒有進程能使用的部分,稱外部碎片
單一連續分配
優點:沒有外部碎片,可以不用內存保護,採用覆蓋技術
缺點:(進程沒用上的)內部碎片,僅能單用戶,單任務,效率很低
固定分區分配
支持多道程序
分區大小相等:死板,適用於控制多個相同對象(工廠生產)
分區大小不等:靈活,按需劃分
每個分區只裝入一道作業,使用==分區說明表(按大小排列)==記錄,進程找到第一個能滿足大小的未分配分區,記得修改分區說明表的狀態!
分區號 | 大小(MB) | 起始地址 | 狀態 |
---|---|---|---|
1 | y | x | 未分配 |
2 | z | x+y | 未分配 |
3 | n | x+y+z | 未分配 |
… | … | … | … |
實現簡單,外部碎片
進程過大時裝不下(可以使用"覆蓋" 技術搶救一下),但內部碎片 效率
動態分區分配
支持多道程序,又稱爲 可變分區分配 :進程裝入內存時根據進程大小動態地建立分區,分區大小和數量可變
數據結構:空閒分區表 和 空閒分區鏈表
分區號 | 大小(MB) | 起始地址 | 狀態 |
---|---|---|---|
1 | l | s | 未分配 |
2 | m | s+l+x | 未分配 |
3 | n | s+l+x+m+y | 未分配 |
… | … | … | … |
表項的排列順序和動態分區分配算法有關,分配後記得修改相應表項狀態
回收時只要有相鄰空閒區就會合併
內部碎片 外部碎片
可以通過 緊湊(或拼湊,Compaction) 技術,“平移”進程塊來解決外部碎片的問題
動態分區分配算法
算法 | 數據結構 | 優點 | 缺點 |
---|---|---|---|
首次適應算法(First Fit) | 地址排序 由低到高 第一個 |
算法開銷小 回收不用再排序 綜合性能最佳 |
從頭開始–> 低地址很多外部碎片–> 查找開銷 |
最佳適應算法(Best Fit) | 空間排序 由小到大 第一個 |
保留大分區 | 越來越多 外部碎片 算法開銷大 |
最壞適應算法(Worst Fit) (或“最大適應算法”) |
空間排序 由大到小 第一個 |
較少外部碎片 | 消耗大分區 大進程不友好 算法開銷大 |
鄰適應算法(Next Fit) | FF算法+循環 從上次查找結束 的位置繼續查找 |
小進程同BF高址留大 | 大進程同WF裝不下 |
非連續分配
支持多道程序的 固定分區分配 和 動態分區分配分別會產生內部碎片 和 外部碎片,“緊湊”算法代價很高----->內存分爲分爲多個大小相等的小分區,再按分區大小拆分進程,實現非連續內存空間存儲,分區越小內部碎片越小
基本分頁存儲管理
內存
每個分區稱爲頁框、頁幀、內存塊、物理塊(多數4KB)
每個都有號碼(頁框號、頁幀號、內存塊號、物理塊號)
進程
被分爲與頁框大小相等的頁(或頁面) ,物理單位
對應的號碼爲頁號
訪問過程
其中假設地址32bit,頁面4KB=212B,按字節尋址,邏輯地址
頁號 | 頁內偏移量 |
---|---|
31~12 | 11~0 |
220-1<3Byte | 使用2的整數冪做頁面大小方便計算 |
每個進程創建一張頁表(慢表)
頁號 =頁表起始地址 + 頁號 3Byte (順序存儲+表項等大=隱藏) | 物理塊號(頁框號) |
---|
表項按頁號順序存儲,每頁可存
但爲了方便查表,常使用4B存儲一個表項(沒有內部碎片1B)
兩級頁表
一個進程最大220個頁面,頁表大小 = 222B = 210 4KB,需要1024個連續的頁框才能存下
局部性原理:一段時間內集中訪問若干頁面–>其他頁面不用常駐內存
再分組:爲離散分配的頁表再建 “頁目錄表” (or 外層頁表 or 頂層頁表)
一級頁號 | 二級頁號 | 頁內偏移量 |
---|---|---|
31~22 (210) | 21~12 (210) | 11~0 (212) |
基本地址變換機構
邏輯地址 轉換 物理地址 的一組硬件機構
快表
時間局部性:被執行的指令很可能再次被執行,被訪問數據很可能再次被訪問(循環指令)
空間局部性:被訪問存儲單元附近的單元很可能近期被訪問(數組)
局部性原理 導致多次重複查詢同一頁號 + 高速緩衝寄存器(cache) = 快表 (TLB,Translation Lookaside Buffer)
命中則只需要“取數據”僅一次內存訪問,未命中則需要"慢表查詢”+“數據訪問"兩次內存訪問
“快表”溢出需要用算法找出可以替換的頁表項
基本分段存儲管理
邏輯單位 進程地址劃分爲若干段(編譯器:段名–> 基址),每段佔用一個連續空間,邏輯地址:
段號 | 段內地址 |
---|
段表
段號(順序存儲+表項等大=隱藏) | 段長 | 基址 |
---|---|---|
2段號位 | 2段內地址位 | 內存地址空間4GB=232B |
同樣可以使用"快表"
基本段頁式存儲管理
基本分頁存儲 | 基本分段存儲管理 |
---|---|
一個邏輯地址=一個物理地址(一維) | 段名+段長(二維) |
物理單位,系統行爲 | 邏輯單位,用戶行爲 |
大小固定=無外部碎片 | 容易實現信息的共享保護 如信號量機制 等“可重入”/“純” 代碼 |
保護部分和共享部分在頁內分不開 | 大小可變=長段沒”坑“,有外部碎片 |
段頁式管理 = 邏輯分段+每段分頁 ,從而同時獲取兩種管理方式的優點
用戶指定
段號 | 段內地址 |
---|
系統根據段內地址分配 頁號 與 頁內地址 得到邏輯地址
段號 | 頁號 | 頁內偏移量 |
---|
段表
段號(順序存儲+表項等大=隱藏) | 頁表長度 | 物理塊號(頁框號) |
---|
頁表
頁號(順序存儲+表項等大=隱藏) | 物理塊號(頁框號) |
---|
三次內存訪問,引入快表{段號;頁號;物理地址}可以減少至一次
空間擴充
覆蓋與交換
覆蓋: (同一個進程中)程序按功能分段(模塊)
用戶必須指明覆蓋的結構,增加用戶負擔
交換: (不同進程間)就是中級調度,換出空間需求大的進程,換入需求小的進程
由就緒態 轉換爲 就緒掛起時,PCB還是常駐內存中的
內存喫緊時,降低系統負荷,反映在缺頁率上
虛擬內存
局部性原理 + 高速緩衝技術
傳統的存儲管理機制 | 虛擬內存技術 |
---|---|
作業一次性裝入內存 大程序無力,併發度下降 |
多次性 |
訪問的局部性 駐留性 --> 浪費資源 |
對換性 |
實際容量=min(內存+外存,最大容量=2CPU尋址位數)
操作系統提供 請求調頁/請求調段+頁面置換/段置換 功能
請求分頁存儲管理
頁表增加了頁面狀態的描述字段
頁號(順序存儲+表項等大=隱藏) | 物理塊號(頁框號) | 狀態位 | 訪問字段 | 修改位 | 外存地址 |
---|---|---|---|---|---|
始址+頁號表項大小 | 物理地址 | 內存中? | 訪問次數 訪問時間 |
被寫? | 文件結構 |
表中有省略
被“擠出快表”(從快表中刪除)的表項要在慢表中修改相應的表項
被”寫“過的表項“修改位”變化,沒被寫過的表項“置換”時可以不用拷貝回外存
I/O操作慢,頻繁置換開銷很大
頁面置換算法
挑選 “內存中暫時用不到的塊” 換出到外存,好的算法缺頁率低,磁盤I/O少
缺頁率=
最佳置換算法(Opt,Optimal)
淘汰最長時間內不會再使用的頁面
訪問順序 | 7 | 0 | 1 | 2 | 0 | 3 | 0 | 4 | 2 | 3 | 0 | 3 | 2 | 1 | 2 | 0 | 1 | 7 | 0 | 1 |
---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|
內存塊0 | 7 | 7 | 7 | 2 | - | 2 | - | 2 | - | - | 2 | - | - | 2 | - | - | - | 7 | - | - |
內存塊1 | - | 0 | 0 | 0 | - | 0 | - | 4 | - | - | 0 | - | - | 0 | - | - | - | 0 | - | - |
內存塊2 | - | - | 1 | 1 | - | 3 | - | 3 | - | - | 3 | - | - | 1 | - | - | - | 1 | - | - |
缺頁統計 | √ | √ | √ | √ | - | √ | - | √ | - | - | √ | - | - | √ | - | - | - | √ | - | - |
7號頁面之後出現時間最晚,被換出,其他類推
缺頁率==45%
無法預知頁面訪問順序無法實現,作爲比較基準
先進先出置換算法(FIFO)
淘汰最早進入的頁面
訪問順序 | 3 | 2 | 1 | 0 | 3 | 2 | 4 | 3 | 2 | 1 | 0 | 4 |
---|---|---|---|---|---|---|---|---|---|---|---|---|
內存塊0 | 3 | 3 | 3 | 0 | 0 | 0 | 4 | - | - | 4 | 4 | - |
內存塊1 | - | 2 | 2 | 2 | 3 | 3 | 3 | - | - | 1 | 1 | - |
內存塊2 | - | - | 1 | 1 | 1 | 2 | 2 | - | - | 2 | 0 | - |
缺頁統計 | √ | √ | √ | √ | √ | √ | √ | - | - | √ | √ | - |
3號頁面最早出現,被換出,其他類推
缺頁率==75%
增加內存塊數可能導致某些訪問順序( 如上 )會出現Belady異常(缺頁率反而變大)
最先進入的通常爲常駐塊( 如main函數等 )
性能最差
最近最久未使用置換算法(LRU,least recently used)
淘汰最早開始沒有被使用的已駐頁面
頁號(順序存儲+表項等大=隱藏) | 物理塊號(頁框號) | 狀態位 | 訪問後計時 | 修改位 | 外存地址 |
---|
訪問順序 | 1 | 8 | 1 | 7 | 8 | 2 | 7 | 2 | 1 | 8 | 3 | 8 | 2 | 1 | 3 | 1 | 7 | 1 | 3 | 7 |
---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|
內存塊0 | 1 | 1 | - | 1 | - | 1 | - | - | - | - | 1 | - | - | - | - | - | 1 | - | - | - |
內存塊1 | - | 8 | - | 8 | - | 8 | - | - | - | - | 8 | - | - | - | - | - | 7 | - | - | - |
內存塊2 | - | - | - | 7 | - | 7 | - | - | - | - | 3 | - | - | - | - | - | 3 | - | - | - |
內存塊2 | - | - | - | - | - | 2 | - | - | - | - | 2 | - | - | - | - | - | 2 | - | - | - |
缺頁統計 | √ | √ | - | √ | - | √ | - | - | - | - | √ | - | - | - | - | - | √ | - | - | - |
7號頁面最早開始沒有被使用,被置換
缺頁率==30%
性能最好,但開銷大,需要硬件支持
時鐘置換算法(CLOCK)
又稱“最近未使用算法(NRU,Not Recently Used)”
被訪問置1,需要置換時,(最多2圈)循環檢查並置零訪問位,淘汰訪問位0的頁面
頁號(順序存儲+表項等大=隱藏) | 物理塊號(頁框號) | 狀態位 | 訪問位 | 修改位 | 外存地址 |
---|
改進型時鐘置換算法
在時鐘置換算法基礎上,不改變修改位狀態,訪問位相同時優先淘汰沒有被修改過的頁面
未修改 = 不用回寫磁盤 = 節省時間
頁號(順序存儲+表項等大=隱藏) | 物理塊號(頁框號) | 狀態位 | 訪問位 | 修改位 | 外存地址 |
---|---|---|---|---|---|
- | - | - | (0 | 0) | - |
第一輪:找(0,0) = {沒訪問,沒修改}
第二輪:沒找到(0,0)就找(0,1) = {沒訪問,有修改},置0訪問位
第三輪:沒找到(0,1)就找(0,0) = {有訪問,沒修改}
第四輪:沒找到(0,0)就第一個(0,1) = {有訪問,有修改}
替換以上步驟找到的頁面
性能最均衡
頁面分配策略
駐留集:系統分配給進程的物理塊集合(採用虛擬存儲技術的系統 駐留集 < 進程大小)
. | 局部置換(自身物理塊) | 全局置換(空閒 或 其他進程非核心物理塊) |
---|---|---|
駐留集大小不變 = 固定分配 | 固定分配局部置換 | ❌ |
駐留集大小可變 = 可變分配 | 可變分配局部置換 | 可變分配全局置換 |
固定分配局部置換:根據進程大小、優先級等參數確定駐留集
可變分配局部置換:根據缺頁率動態調整駐留集大小,只能置換自己的頁
可變分配全局置換:只要缺頁一定得到新的物理塊,先找空閒塊,再找其他進程非核心(未鎖)塊
調入時機
1.預調頁:= 空間局部性預測,或用戶指定,主要用於首次調入(運行前調入)
2.請求調頁 = 缺頁 才 調頁,磁盤IO開銷大
調入源頭
抖動(顛簸):同一個頁面頻繁的換入換出內存
原因可能是駐留集不夠,導致頻繁訪問的頁面放不下,催生出了 = = 》
(Denning)工作集:某段時間內(窗口尺寸) 進程實際訪問的頁面集合
根據工作及調整駐留集大小(駐留集<工作集 便會抖動),或置換駐留集中的非工作集頁面
請求分段存儲管理
請求段頁式存儲管理
地址轉換
相對地址=邏輯地址
絕對地址=物理地址
尋址空間 = 2地址總線位
尋址範圍 = 0x00 ~
按字節尋址
存儲單元 = 1Byte = 8 bit =最小的編址
按字尋址
存儲單元 = 1 Word = Byte
鏈接方式
得到完整的邏輯地址
靜態鏈接
鏈接—>(.exe)—>裝入—>內存
裝入動態鏈接
(.obj)—>裝入+鏈接–>內存
運行動態鏈接
運行時—>需要(.obj) or (.lib) —>鏈接—>內存
可以共享模塊,易於修改
裝入方式
地址的轉換:邏輯地址—>物理地址
絕對裝入
(.cpp){邏輯地址} —> 編譯 —> (.obj){物理地址}
單道程序環境
靜態重定位
又稱 可重定位裝入
(.cpp){邏輯地址} —> 編譯 —> (.obj){邏輯地址} —> 裝入 —> 內存{物理地址}
要求連續的全部內存空間,運行期間更不可移動!
多道批處理系統
動態重定位
又稱 動態運行時裝入
(.cpp){邏輯地址} —> 編譯 —> (.obj){邏輯地址} —> 裝入 —> 內存{邏輯地址} —> 執行時
允許進程移動,分配不連續存儲區,可以共享程序段!!
現代操作系統
存儲保護
保證進程互不干擾
方法一:cpu{上下限寄存器}
方法二: