在多工作業系統中,當系統需要載入新的頁面到主記憶體(main memory)時,如果所有記憶體框架(frames)都已被佔用,就必須選擇一個現有的頁面將其換出,這個被選中的頁面稱為「受害者頁面」(victim page)。為了盡可能降低頁面置換的頻率,也就是減少 Page Fault 的發生,作業系統會採用不同的頁面替換演算法來決定哪個頁面應該被換出。
FIFO 演算法的概念非常直觀:最早被載入到記憶體中的頁面,也最先被替換。它使用一個佇列(Queue)結構來管理頁面的順序,隊伍頭的頁面是等待最久的,因此在發生 Page Fault 時,會優先被換出。
優點: 實作簡單,只需要記錄頁面進入記憶體的順序。
缺點:
範例:
Reference String: 1, 2, 3, 4, 1, 2, 5, 1, 2, 3, 4, 5
Frame: 3
Page Fault 次數可能比 Frame=4 還低(違反直覺)。
OPT 演算法是理論上的最佳選擇。它會檢視未來所有頁面的存取需求,然後選擇在未來最久不會被使用的頁面來替換。這種預測性的選擇策略可以確保 Page Fault 的發生次數達到理論上的最小值。
優點: 能夠達成最低的 Page Fault 率,常用於評估其他演算法的效能。
缺點: 由於需要「預知」未來的存取行為,在實際的作業系統中無法實現。
LRU 演算法是 OPT 的一種實際近似。它基於時間局部性(Temporal Locality)原則:如果一個頁面在近期被頻繁使用,那麼在不久的將來也很可能再次被使用。因此,它會選擇最久沒有被使用過的頁面來替換。
優點: 表現良好,Page Fault 率接近理想值,能有效利用程式的局部性原則。
缺點: 實作複雜且開銷大,因為它需要額外的硬體或軟體來追蹤每個頁面的「最近使用時間」。常見的實作方式有:
由於完整 LRU 的實作開銷過大,實務上常採用其近似演算法來取得效能與開銷的平衡。
這是一種最簡單的近似。每個頁面都有一個由硬體提供的參考位元(Reference Bit),當頁面被存取(讀或寫)時,硬體會自動將其設為 1。作業系統會定期將所有位元清為 0。
優點: 實作簡單,開銷小。
缺點: 只能判斷頁面是否被使用過,無法得知其具體的使用順序或時間間隔。
此方法在參考位元的基礎上加入了時間的概念。每個頁面除了參考位元,還配備一個 8 位元的暫存器。作業系統會定期(例如每 100 毫秒)執行以下動作:
這樣一來,這個 8 位元暫存器會記錄頁面在過去一段時間內的使用頻率和時間序列。數值越小,代表該頁面越久沒有被使用,也就越適合被替換。
此演算法結合了 FIFO 的簡單性和參考位元的概念。它將所有頁面組織成一個環狀佇列,並使用一個指標(類似時鐘的指針)指向下一個要檢查的頁面。
這種機制讓經常被使用的頁面有機會留在記憶體中,避免了 FIFO 的主要問題,同時又比完整 LRU 的實作成本低。
在虛擬記憶體系統中,框架(Frame)是實體記憶體的最小分配單位。一個程式的頁面(Page)必須載入到框架中才能被執行。當有多個程式競爭有限的框架資源時,作業系統需要採取一套策略來進行分配。
在分配框架給各個程式前,作業系統會先將部分框架保留給自己使用,以存放核心程式碼(kernel code)、系統資料結構以及 I/O 緩衝區等。剩餘的框架才會被分配給使用者程式。這個分配過程主要考量以下幾點:
在確定了最小框架數量後,作業系統通常會採用以下幾種策略來分配其餘的框架:
此方法在程式載入時,就為其分配一個固定的框架數量。此後,這個數量不會再改變。
動態分配允許程式在執行過程中,根據其 Page Fault 的頻率來動態調整所分配的框架數量。
舉例:系統有 128 個 Frame,OS 使用 35 個 → 剩下 93 個 Frame 給使用者程式。
例子:
某 CPU 架構執行一條指令可能需要同時存取:
- 1 個 Frame → 存放指令本身。
- 1 個 Frame → 存放操作數(operand)。
- 1 個 Frame → 存放間接參考(indirect addressing)。
→ 每個程式至少需要 3 個 Frame,否則可能在指令執行中途就發生 Page Fault。
在虛擬記憶體系統中,抖動(Thrashing)是一種嚴重的效能問題,它發生在系統將大部分時間花在頁面置換(paging)上,而不是執行程式的真正指令。當系統的記憶體資源無法滿足正在運行的程式的需求時,就會發生這種現象。
當作業系統為一個程式分配的實體記憶體框架(Frame)數量太少,無法容納其**局部性(Locality)**所需的頁面時,抖動就可能發生。局部性指的是程式在某個時間點內,其存取行為會集中在少數幾個頁面上。如果這些重要的頁面無法同時被載入到記憶體中,會發生以下惡性循環:
問題的根源往往在於作業系統的多工處理排程策略。當系統偵測到 CPU 使用率下降時,它通常會誤認為是因為沒有足夠的程式可以執行,因此會嘗試增加新的程式來提高 CPU 利用率。然而,在抖動的狀態下,CPU 的空閒並非因為缺乏工作,而是因為所有程式都在等待 I/O 操作完成(即等待頁面置換)。當新的程式被加入時,它會從本來就不足的記憶體框架池中分走一部分資源,使得現有程式和新程式都因為缺乏足夠的記憶體而產生更頻繁的 Page Fault。這導致所有程式的效能都急劇下降,最終使系統陷入崩潰狀態。
工作集指的是程式在一個固定的時間視窗(
Delta)內最常存取的頁面集合。此模型的核心思想是:作業系統會追蹤每個程式的工作集,並確保其擁有足夠的框架來容納整個工作集。
PFF 是一種更直接的動態框架分配策略。它不計算複雜的工作集,而是直接監控每個程式的 Page Fault 發生率,並根據這個比率來調整其框架分配。
PFF 策略能即時反應程式的記憶體需求變化,並有效地調整框架分配,從而防止抖動的發生。這兩種策略雖然實作上各有挑戰,但它們都體現了現代作業系統在記憶體管理中,平衡資源分配與效能的核心思想。
在現代作業系統中,記憶體壓縮(Memory Compression)是一種先進的技術,用來應對記憶體壓力。它的核心思想是在實體記憶體(RAM)即將用盡時,不急於將頁面寫入速度緩慢的硬碟(Swap Out),而是將一些不常用頁面的內容壓縮後,繼續保存在 RAM 中。這樣做能釋放出額外的實體記憶體空間,同時避免了昂貴且耗時的磁碟 I/O 操作。
傳統的虛擬記憶體管理依賴於分頁(Paging),當記憶體不足時,作業系統會將不常用的頁面從 RAM 移動到硬碟上的交換區(Swap Space)。
硬碟的存取速度比 RAM 慢了數萬倍。頻繁的頁面換出(Swap Out)和頁面換入(Swap In)會造成嚴重的系統延遲,甚至導致抖動(Thrashing),讓系統幾乎無法運作。
記憶體壓縮則提供了一種更為聰明的解決方案:利用 CPU 的計算能力來換取 I/O 效能的提升。因為執行壓縮與解壓縮演算法的成本,遠低於從磁碟讀寫資料的成本,所以整體系統的反應速度會顯著加快。
項目 | 傳統分頁 | 記憶體壓縮 |
---|---|---|
作法 | 將 page 寫到磁碟 (swap) | 將 page 壓縮後保留在 RAM |
效能 | 慢(I/O 成本高) | 較快(壓縮成本低於 I/O) |
適用場景 | 桌面系統、傳統伺服器 | 手機、筆電、現代 OS |
預先載入(Prepaging)是一種用於優化虛擬記憶體系統效能的技術。它旨在解決需求分頁(Demand Paging)在程式啟動或從暫停狀態恢復時,可能導致的大量頁面錯誤(Page Fault)問題。在傳統的需求分頁模型中,程式的頁面只會在被需要時才被載入記憶體。這導致程式剛啟動時,由於沒有任何頁面在記憶體中,每條指令或資料存取都可能觸發 Page Fault,形成一個「Page Fault 洪峰」,嚴重影響程式啟動速度。預先載入則是一種主動式的策略。它透過預測程式在不久的將來會需要哪些頁面,並在程式實際發出請求之前,就將這些頁面一次性地載入到記憶體中。
成本 vs 效益分析:
假設系統預先載入 s 頁:有 α 比例頁面最終被真正使用。
則:
* 成本 (Cost) = 載入沒使用的頁面數量 = s × (1 – α)
* 效益 (Benefit) = 避免的 Page Fault 次數 = s × α
* 當 α → 1(預測準確) → 預載效益高。
* 當 α → 0(預測失誤) → 浪費記憶體與 I/O。
優點:減少程式啟動時的 Page Fault 洪峰。也加快系統回應時間,特別是大型程式或頻繁暫停/恢復的程式。
缺點:若預測錯誤,會浪費 I/O 與記憶體空間。且難以百分之百準確預測,實務多採取保守策略(僅預載鄰近頁面)
在虛擬記憶體系統中,頁面大小(Page Size)是一個基礎且關鍵的設計參數。它決定了虛擬記憶體和實體記憶體被劃分的單位大小。這個看似簡單的選擇,會對整個系統的效能產生廣泛而深遠的影響。在虛擬記憶體系統中,頁面大小(Page Size)是一個基礎且關鍵的設計參數。它決定了虛擬記憶體和實體記憶體被劃分的單位大小。這個看似簡單的選擇,會對整個系統的效能產生廣泛而深遠的影響。
Page Table 是用來存放虛擬位址與實體位址對應關係的資料結構。
內部碎裂指的是頁面中未被使用的空間。當程式的資料大小不是頁面大小的整數倍時,最後一頁會產生未使用的浪費空間。
當發生 Page Fault 時,需要將整個頁面從磁碟讀入記憶體。
局部性原則是虛擬記憶體系統運作的基礎。它假設程式在一段時間內會集中存取某些頁面。
Page Fault 次數與每次載入頁面的資料量有關。
考量因素 | 小頁面較佳 | 大頁面較佳 |
---|---|---|
Page Table 大小 | ❌ 頁數多 → Page Table 變大 | ✅ 頁數少 → Page Table 縮小 |
Internal Fragmentation(內部碎裂) | ✅ 記憶體浪費少,每頁不易留空白 | ❌ 浪費空間多,部分頁面可能沒填滿 |
I/O 傳輸效率 | ❌ 多次 I/O,傳輸開銷高 | ✅ 一次讀寫更多資料,效率高 |
Locality 精準度 | ✅ 更精準,避免載入不必要資料 | ❌ 精準度低,可能載入多餘資料 |
Page Fault 次數 | ❌ 頁面數多,換頁頻繁 | ✅ 頁面數少,換頁次數減少 |