1. 程式人生 > >記憶體管理的基本思想與演算法

記憶體管理的基本思想與演算法

介紹作業系統是如何來管理記憶體資源。

層次化儲存體結構

計算機的儲存體系

  • 暫存器(register)
    • 在CPU內部,非常快速,昂貴
  • 快取記憶體(cache)
    • 非常快速,昂貴,容量小,易失性
  • 主存(RAM)
    • 中等速度,中等價格,易失性
  • 外存
    • 容量大,速度慢,種類多,不易失

作業系統的工作就是協調這些儲存器的使用,管理儲存器的部分程式被稱為儲存管理器

  • 記錄儲存使用狀況
  • 分配、回收儲存資源
  • 資料的裝入與寫回

儲存管理系統分類

在執行期間,程序需要在記憶體和磁碟之間換進換出的系統(交換和分頁)和不需要換進換出的系統

不需要換進換出的系統

  • 特點:程序被調入執行後,它將始終位於記憶體中,直至執行結束
  • 沒有交換和分頁的單道程式
  • 固定分割槽的多道程式

不需要換進換出的系統實現起來是最簡單的,但無法做到併發等現代作業系統的高階功能。

基本的儲存管理

單道程式儲存管理

  • 同一時刻只執行一道程式應用程式和作業系統共享儲存器

  • 相應地,同一時刻只能有一個程序在儲存器中執行。

  • 一旦使用者輸入了一個命令,作業系統就把需要的程式從磁碟貝到儲存器中並執行它;在程序執行結束後,作業系統顯示出個提示符並等待新的命令。當收到新的命令時它把新的程式裝入儲存器,覆蓋掉原來的程式

實現方案

將作業系統和應用程式在RAM上存放位置的不同分為以下三種結構:

52764925885

固定分割槽的多道程式系統

將記憶體劃分為n個分割槽(可能不相等),分割槽的劃分可以在系統啟動時手工完成。

實現方案

  1. 每個分割槽分別有一個執行佇列

    • 當一個作業到達時,可以把它放到能夠容納它的最小的分割槽的輸入佇列中
    • 這會造成小分割槽的佇列是滿的,而大分割槽的輸入佇列卻是空的
  2. 各分割槽共享同一個輸入佇列

    如果選擇小程序先執行,則會浪費記憶體空間;而如果選擇大程序執行,則對小程序不利。

    • 一種演算法是至少保留一個小分割槽,這樣小程序就可以直接執行不與大程序競爭
    • 另一種方式是制定一條規則:規定一個程序被忽略的次數不能超過k次

重定位和儲存保護

多道程式引發了兩個很重要的問題:

  1. 當一個程式被連結時,必須知道程式將在記憶體的什麼地方執行
  2. 當一個程式執行時,它只能訪問自己的記憶體空間

重定位

使用相對地址進行連結。

當一個程式被裝入記憶體時,直接對指令程式碼進行修改,一次性實現檔案內的相對地址到記憶體中絕對地址之間的轉換(一般為線性)

在裝入時重定位並沒有解決保護問題,一個惡意的程式總可以生成一條新指令去訪問任何它想訪問的地址

地址保護

  1. 每個記憶體塊分配4位的保護碼,PSW中包含一個4位的金鑰,若執行程序試圖對保護碼不同於PSW中金鑰的主存進行訪問,則由硬體引起一個陷入

  2. 另一種解決方式是在機器中增加兩個特殊的硬體暫存器,基地址(base)和邊界(limit)暫存器

    程式分割槽的起始地址儲存在基地址暫存器中

    分割槽的長度儲存在邊界暫存器中

    當訪問記憶體單元時,直接用基地址加上指令地址訪問

    缺點是每一次記憶體訪問都增加了一次加法和比較操作。

交換技術(swapping)

隨著程式越來越大,我們已經無法一次性把程式全部放到記憶體同時執行,因此產生了兩種技術:交換技術(swapping)和虛擬儲存器(virtual memory)

原理

把各個程序完整地調入主存,執行一段時間,再放回到磁碟上,過段時間再調入執行。

可採用固定分割槽和可變分割槽。

記憶體緊縮(memory compaction)

當交換在主存中生成了多個空洞時,可以把所有的程序向下移動至相互靠緊,從而把這些空洞結合成一大塊。

但這樣會造成CPU資源浪費。

使用可變記憶體策略來減少程序移動或換入換出的次數。

支援可變記憶體策略

如果預計大多數程序在執行時都要增長,那麼可以在程序被換入或移動時分配多一點的記憶體,從而減小系統開銷。

但如果程序需要換出磁碟,只需要交換程序實際佔用的記憶體內容。

實現方案

基於點陣圖的儲存管理

記憶體被劃分為可能小到幾個字或大到幾千位元組的分配單位,每個分配單位對應於點陣圖中的一位,0表示空閒,1表示佔用(或者反過來)。

52766558313

點陣圖的大小僅僅取決於記憶體分配單位的大小。

缺點:在點陣圖中查詢指定長度的連續0串是一個緩慢的操作。

基於連結串列的儲存管理

跟蹤記憶體使用的另一個方法是維持一個已分配和空閒的記憶體段的連結串列

連結串列中的每一個表項都包含下列內容:

  • 指明是空洞(H)還是程序(P)的標誌
  • 開始地址、長度
  • 指向下一個表項的指標。

記憶體分配演算法

首次適配演算法(first fit)

  • 儲存管理器沿著記憶體段連結串列搜尋直到找到一個足夠大的空洞

下次適配(next fit)

  • 每次找到合適的空洞時都記住當時的位置,在下次尋找空洞時從上次結束的地方開始搜尋,而不是每次都從頭開始

最佳適配演算法(best fit)

  • 試圖找出最接近實際需要的大小的空洞,而不是把一個以後可能會用到的大空洞先使用
  • 實際效能其實很差,因為會造成很多空洞

  • 每次被呼叫時都要搜尋整個連結串列,因此會比首次適配演算法慢

最壞匹配演算法(worst fit)

  • 在每次分配時,總是將最大的那個空閒區切去一部分,分配給請求者

程序連結串列和空閒連結串列分離

  • 這樣可以加快連結串列的查詢速度
  • 但使得記憶體的回收變得更加複雜,速度更慢

快速匹配演算法(quick fit)

  • 為一些經常被用到長度的空洞設立單獨的連結串列
  • 快速適配演算法尋找一個指定大小的空洞是十分迅速的,但在一個程序結束或被換出時尋找它的鄰接塊以檢視是否可以合併是非常費時間的

虛擬儲存管理

基本思想

  • 作業系統把程式當前使用的那些部分保留在儲存器中,而把其他部分儲存在磁碟上。
  • 程式的程式碼、資料、棧可以超過實際可用的實體記憶體的大小

分頁技術(paging)

虛地址空間被劃分成稱為頁面(pages)的單位,在物理儲存器對應的單位稱為頁框(page frames),頁和頁框總是同樣大小的。

由程式產生的地址被稱為虛地址(virtual addresses),他們構成一個虛地址空間(virtual address space)

  • 在使用虛擬儲存器的情況下,虛地址不是被直接送到記憶體總上,而是送到儲存管理單元(MMU),它在CPU中,其功能是把虛地址對映為實體地址
  • 52766632264

缺頁故障(Page Fault)

當訪問未有對映的虛擬頁,會引發陷入,這個陷入稱為缺頁故障。

作業系統找到一個很少使用的頁框並把它的內容寫入磁碟,隨後把需引用的頁取到剛才釋放的頁框中,修改對映,然後重新啟動引起陷入的指令。

頁表(Page Table)

虛地址被分成虛頁號(高位)偏移(低位)兩部分,

  • 虛頁號被用做頁表的索引以找到該虛頁對應的頁表項,從頁表項中可以找到頁框號(如果有的話)。
  • 頁框號被拼接到偏移的高位端,形成送往記憶體的實體地址。

主要問題

  1. 頁表可能會非常大
  2. 地址對映必須十分迅速

多級頁表

使用多級頁表來解決頁表過大的問題。

因為區域性性原理,程式實際訪問的地址空間是很小的一部分,因此可以多次對映來將不需要的頁表儲存在磁碟中。

52766780259

優點

  • 避免將程序的所有頁表項一直儲存在記憶體中

缺點

  • 需要多次訪問記憶體,以查詢頁表

頁表項的結構

52766797005

頁框號

  • 物理頁面號

有效位

  • 這一位是1時這個表項是有效的可以被使用,如果是0,表示這個表項對應的虛頁現在不在記憶體中,訪問這一位為0的頁會引起Page Fault

保護位

  • 指出這個頁允許什麼樣的訪問。
  • 在最簡單的形式下這個域只有一位,0表示讀寫,1表示只讀。一個更先進的安排是使用三位,各位分別指出是否允許讀、寫、執行這個頁。

修改位和訪問位跟蹤頁

  • 在一個頁被寫入時硬體自動設定修改位,如果一個頁已經被修改過,則必須把它寫回磁碟,否則只用簡單地把它丟棄就可以了
  • 訪問位在該頁被引用時設定,被用來幫助作業系統在發生頁面故障時選擇淘汰的頁,不再使用的頁要比在使用的頁更適合於被淘汰

禁止快取位

  • 這個特性對那些對映到裝置暫存器而不是常規記憶體的頁面是非常重要的。

TLB

由於訪問頁表(記憶體中)依然不夠快,因此在CPU中有一小部分頁表的拷貝,這部分頁表是由最近訪問頁的頁表項組成,稱為TLB

當一個虛地址被送到MMU翻譯時,硬體首先把它和TLB中的所有條目同時(並行地)進行比較;如果找到了並且這個訪問沒有違反保護位,它的頁框號將直接從TLB中取出而不用去查頁表。

反置頁表

物理儲存器的每個頁框對應一個頁表項,而不是虛地址空間中的每個虛頁對應一個頁表項。

優點:節省大量為儲存頁表所需要記憶體空間

缺點:查詢過程複雜

頁面替換演算法

動機

當發生缺頁中斷時,需從磁碟上調入相應的頁面,然而記憶體已滿,需要選取記憶體中的頁面,將其換出,並裝入新頁面。

如何從眾多的頁面中選取被置換的頁面?

  • 為此提出了各種演算法
  • 可以應於快取塊的置換、Web緩衝區的更新等

頁面替換演算法

The Optimal Page Replacement Algorithm

  • 選擇等待時間最長的那個頁面被替換。
  • 無法實現,因為無法知道一個頁面還要等待多久被訪問。

The Not Recently Used Page Replacement Algorithm

  • 統計訪問位和修改位,在一個時鐘週期內,選擇未被訪問也未被修改的頁面被替換
  • 在一個時鐘週期結束後,訪問位會被清零

FIFO Page Replacement Algorithm

不是很好的演算法,最先進入的頁面也有可能是經常訪問的頁面

The Second Chance Page Replacement Algorithm

  • 對FIFO的改進,如果訪問位為1,那麼曾經訪問過,就把其清零,然後把頁面放到連結串列的尾端,修改裝入時間。
  • 如果訪問位為0,則直接淘汰。
  • 實際上式尋找古老而且從上一次時鐘中斷以來未被訪問的頁面

The Clock Page Replacement Algorithm

  • 改進二次機會演算法,使用環形連結串列形式,避免了連結串列指標移動。

Least Recently Used Algorithm

  • 將記憶體中最久未被訪問的頁面淘汰
  • 每次訪問都會造成連結串列節點更新,開銷較大。
  • 可以使用硬體支援來加速
  • 使用軟體模擬(老化)
    • Not Frequently Used Algorithm

參考資料

  1. Operating System:Design and Implementation,Third Edition