作業系統——記憶體管理學習筆記

頭髮是我最後的倔強發表於2020-09-11

作業系統——記憶體管理

Basic memory management

Base and Limit register

在這裡插入圖片描述

將上圖這塊稱為MMU

Swapping

在這裡插入圖片描述

作業系統中的記憶體是動態分配的,如圖所示:

  1. A程式啟動,佔用一部分記憶體
  2. B程式啟動,佔用一部分記憶體
  3. C程式啟動,佔用一部分記憶體
  4. A程式結束,又會將之前A佔用的記憶體釋放
  5. 隨後又啟動D程式,佔用掉一部分記憶體
  6. B程式結束,釋放掉B佔用的記憶體
  7. 再啟動A,這時又會劃分給A一部分記憶體

這些動態的對記憶體的規劃,就要用到swap交換記憶體,所以一般在linux系統中對交換分割槽的分割槽大小是和記憶體大小一致,或者記憶體的兩倍,就是為了保證交換分割槽足夠大,且高效。

在這裡插入圖片描述

如b圖,在程式A中,程式碼段存在A-Program中,是相對固定的大小。資料段A-Data挨著程式碼段,當new資料的時候資料段就會增長。在這個程式的地址空間的高階地址會放一個A-Stack,當每次呼叫一個函式,就會壓入A-Stack中(壓入棧的叫棧幀),當從函式退出的時候就會彈棧。當資料段和棧碰在一起的時候就溢位了。

Virtual memory

Memory Management with Bit Maps

在這裡插入圖片描述

Memory Management with Linked Lists

在這裡插入圖片描述

  1. 用Bit Map管理記憶體

    ​ 如圖(b),A、B、C、D、E表示程式,陰影表示未被分配的記憶體區域。將記憶體劃分為一個一個的小塊,如A程式佔用了5個小塊。在作業系統的記憶體中維護一張表map,表中每一個bit對應記憶體中的一個小塊。入A程式與表的第一行的對應,如果該小塊記憶體被佔用就用1來表示,如果未被佔用就用0來表示。這樣維護一張Bit Map就可以管理記憶體。

  2. 拉一張連結串列來管理記憶體

    ​ 如圖(c),連結串列中一個結點有四個資料:第一個為P/H,如果是P則表示是程式在使用這塊記憶體(Process),如果是H,則表示這塊記憶體未被分配(Hole)。第二個為起始位置,表示這個結點所表示的這塊記憶體的起始位置。第三個表示長度,表示這個結點所表示的記憶體所佔用的長度。第四個指示下一個結點。

    ​ 當程式所使用的記憶體被收回後,應該維護這個連結串列使得保持一致,不可能出現兩個Hole連在一起,當一個程式被釋放記憶體後,如果左右有Hole,應該將其合在一起,改變起始位置和長度。

Virtual Memory Paging

​ 當執行一個佔用記憶體很大的程式時,由於實體記憶體不夠用就需要用到虛擬記憶體。把physical記憶體分成塊,一會兒讓這個程式的這部分用,一會兒讓另外一部分用。這樣就會產生一個類似於swap的從記憶體和硬碟裡的轉化的過程。

在這裡插入圖片描述

​ 這裡的MMU(Memory management unit)是將虛擬地址轉化為實際的實體地址,轉化的過程比最開始的那個複雜。首先得知道你要訪問的記憶體在不在實體記憶體裡面,如果不在physical memory裡面,就把你要訪問的地址在記憶體中找個地方載入進來,然後才再去訪問它。把不存在的地址載入進記憶體這件事需要硬體來做,也需要作業系統(作業系統的一個功能——請求分頁,用來支援虛擬記憶體的一個功能)來做。

​ 要知道這個程式裡的哪些頁在記憶體裡面,哪些不在,如果在,在記憶體的什麼地方,就需要用到虛擬記憶體裡面用到的一個技術——分頁(Paging)。MMU會和分頁結合起來完成這個虛擬記憶體。

分頁,就是把記憶體分成固定大小的頁幀,把程式裡面訪問的空間也分成一個一個的頁,每個頁對應一個頁幀,每一個頁幀在實體記憶體可以是不連續的,但是有一個辦法可以知道頁到頁幀之間的轉換,這個機制就叫頁表(頁表存放在作業系統裡面)。每個程式都有一個PCB,PCB裡有一個資料結構就指向這個程式的頁表,每個程式要執行都要一個頁表,每個程式的頁表都是不一樣的。

在這裡插入圖片描述

Address Translation Architecture

​ logical address也就是虛擬地址,是一個二進位制數,低位d表示偏移量直接拿過去,拿到高位(就是p,頁幀的編號),在page table中把p作為下表找到對應的f,和剛剛的d拼到一塊就是實體地址。

​ 這張page table是作業系統在載入這個程式的時候建起來的,把這個程式需要用到的頁都載入進這個表。

在這裡插入圖片描述

​ 缺頁中斷:page table裡的f並不是都建好,它是建了一部分,所以有可能會出現:用邏輯地址p查表發現f沒有,也就是說要訪問的物理頁不在記憶體裡面,這個時候就會產生缺頁中斷。就會跑到作業系統裡,作業系統就會找到一塊記憶體,然後把要訪問的頁從磁碟裡面放到記憶體裡面,然後把這個地址填上,重新執行這條指令。

下圖是一個MMU,下面是邏輯地址,上面的是實體地址。實際的page table並不是和圖中一樣只有兩部分,Present/absent表示這一項所對應的實體地址在或者不在,1表示在,0表示不在,不在就會產生缺頁中斷。

Internal operation of MMU with 16 4KB pages

實際圖中偏移量的位元決定了頁面的大小,比如下圖的偏移量是12個bits,所以頁面大小為4Kb(12個bit,就是2^12 = 1024*4,1 kb = 1024 bit,所以就是4kb了),如果是13個bits,那就就要double一下,即8Kb。

在這裡插入圖片描述

​ 由於頁表也在記憶體中,所以這種方式需要訪問兩次記憶體:第一次查表找到實際的實體地址,第二次訪問真正的記憶體。所以在時間上會稍慢一些。

​ 上面的方案是查的時候先有一個頁幀的編號,再有一個偏移量,但這時候程式的頁表會很大,很多時候頁表中很多項都沒有載入到記憶體裡面,那些項在作業系統記憶體中佔著,但是沒有資料,沒有對應關係,佔的空間會很大。所以將頁表分為二級頁表

在這裡插入圖片描述

​ 二級頁表的PT1是頁目錄(Top-level page table)的下標,用它可以找到頁表的位置,再用PT2在找到的頁表中找到頁幀,再結合偏移量offset找到physical memory。

​ PT1對應的頁表在記憶體中的位置可以是空的,所以Second-level page table裡的某些表可以不放在記憶體裡面,也就是用Top-level page table裡的一項代替Second-level page table裡的一張表,減少了記憶體的大小。當然還可以分成三項、四項......但是這樣的話所訪問記憶體的次數就會增加,所以是用時間換取空間。

Typical page table entry

下圖是一個典型的頁表項,表示一個頁表項可以存什麼資訊。

在這裡插入圖片描述

  1. Present/absent:佔一個bit位,如果是0表示這一頁在記憶體中不存在,如果是1表示在記憶體中存在
  2. Page frame number:如果Present/absent為1,則表示這一頁的頁幀,如果為0,則表示這一也在swap分割槽(硬碟中)中的位置。
  3. Protection:保護位,儲存一些保護資訊,表明這個頁的許可權資訊,比如:只讀的、讀寫的......
  4. Modified:如果物理頁幀做過修改,就將這個位置位。
  5. Referenced:每次對這個頁面訪問的時候,就會置這個位,用來表示這個頁面有沒有被訪問過
  6. Caching disabled:是否允許cache這個頁

TLBs——Translation Lookaside Buffers

在這裡插入圖片描述

​ 為了提高效率,在MMU的這一套硬體系統里加了一個cache(TLB),在一個程式中第一次通過邏輯頁查詢,查到頁幀(Page frame)、Protection、Modified,然後將其存到這個TLB中,等下次訪問這個邏輯頁的時候就不用去查表,直接在TLB中就可以返回頁幀,以達到加速查詢。TLB中還有一項Valid,如果為0則表明這一項是無效的,是1才是有效的。

​ 可以看出這一張TLB中所有的Virtual page是針對一個程式的,所以當出現程式切換,這整個TLB的內容全就無效了,因為不同程式的對應關係也不同。所以程式切換的開銷很大。程式也因為這個TLB所以越跑越快,因為整個表建立好後就快速了。

Inverted Page Tables

在這裡插入圖片描述

​ 原來的是根據邏輯頁去查詢實際的物理頁,最左邊的圖,表中有2^52個頁,根據邏輯地址去找,找到某一項。這樣的話,這樣的頁表是針對每個程式都有這樣一個頁表,這樣一個頁表中可能大部分的項都是空的。

​ 反向頁表,假如只要256MB的實體地址,就有2^16個4KB大小的page frames(頁幀),那麼就看這麼多物理的頁幀到底是哪個虛擬的頁或者哪個程式在用的,把Virtual page做一個hash得到一個hash值,hash的範圍就這個物理的頁幀的範圍裡面,得到hash值後就能找到一個列表,這個列表裡面就對應了一個Virtual page和physical page 的對應關係。如果hash出來這個值找到了一個連結串列(至於為什麼是連結串列,是為了解決hash衝突),那就找到了這個物理頁和邏輯頁的對應關係,如果沒找到就說明這個邏輯頁不存在。

Page replacement algorithms

Optimal Page Replacement Algorithm

​ 最優的頁面替換演算法就是能看到未來,被替換的頁面是記憶體中未來被使用最少的頁面,但這種演算法雖然是最優的,卻是不可實現的,因為未來是無法預知的。這個演算法可以用來評估其他的演算法。

Not Recently Used Page Replacement Algorithm

  • Each page has Reference bit,Modified bit
    • bits are set when page is referenced, modified。當這個頁面被訪問的時候就將referenced位置1,當這個頁面被修改的時候就將Modified置1。
    • 這兩個位也可能被清。比如後臺執行的page Demain的程式,週期掃描這個頁表,當發現某些被modified,就嘗試把這些頁回寫到磁碟裡,然後將Modified清0。
    • 有時候也會定期的把reference清0,配合頁面替換演算法,清的時間是知道的,當下次查這個reference的時候發現又被置1,說明至少在清的時間到再次查的時間裡被訪問過。
  • Page are classified(分類)
    1. not referenced,not modified
    2. not referenced,modified(這裡做一個解釋:有可能被訪問且修改後,referenced被清0了,但modifies沒有被清,也就是沒寫到磁碟裡去)
    3. referenced,not modified
    4. referenced,modified
  • NRU removes page at random
    • from lowest numbered non empty class
    • 就是按上面分的類,從低到高替換(非空的)。

FIFO Page Replacement Algorithm

​ 比較簡單,就是維護一個LinkedList,按頁面進入記憶體的順序將這寫頁面連結起來,每次替換的時候替換掉最先進入到記憶體的頁面,這種雖然簡單但並不實用。

Second Chance Page Replacement Algorithm

在這裡插入圖片描述

​ 基於前面的FIFO Page Replacement Algorithm,A頁面是最先進入到記憶體的頁面,當需要替換頁面的時候找到A,然後檢查A的Referenced位,如果被置1,則將A放到隊尾並將Referenced清0,若此時的隊頭是B,且B的R位沒有被置則將其替換。

​ 等到再次輪到A的時候,發現A的R位沒有被置就說明在這段時間裡A沒有被訪問過。這就相當於給了A第二次機會,所以叫Second Chance Page Replacement Algorithm

The Clock Page ReplacementAlgorithm

在這裡插入圖片描述

​ 用一個指標指向一個頁面,當發生缺頁需要替換的時候先判斷指標指向的頁的R位是否為1,如果為1則清0,將指標挪到下一個頁面上,再判斷如果為1繼續清0挪指標呢,如果為0則將其替換。不同於Second Chance的是沒有維護一個以時間為標準的佇列,但也給了第二次機會。

Least Recently Used(LRU)

​ 這個演算法是每次替換的都是很長時間未被使用的頁面,一種可能的實現方法就是維護一個連結串列,但每次訪問記憶體都要更新這個連結串列開銷過大。還有一種方法上就是給page table加一項count,每次訪問這個頁面就給count++,通過這個count來表示這個頁面被訪問的次數。

Simulating LRU in Software (1)

在這裡插入圖片描述

​ 一個陣列,當訪問頁面x的時候,將第x行全部置為1,第x列全部置為0,按此順序模擬0、1、2、3、2、1、0、3、2、3,可以觀察到到d圖時第0行已經全部變為0,說明當一個頁面很久不被訪問的時候會由於其他頁面被訪問而將其所在行的“1”一列一列的全部置為0,由此可以根據某個頁面所在行的大小判斷是否替換這個頁面。

​ 可能會有這個疑問:如果訪問完頁面a,然後一直訪問頁面b,那麼多次訪問過b後,a也是很久沒有訪問,但其所在行加起來還是很大。這個屬於理解錯誤,如果一直訪問同一個頁面那根本就不用用到頁面替換演算法啊,頁面替換是當要訪的頁面不在記憶體中產生缺頁的時候才用的,一直訪問同一個頁面那最多發生一次頁面替換,之後這個頁面肯定已經存在與記憶體中了。

Simulating LRU in Software (2)

在這裡插入圖片描述

​ 在第一個時間裡針對0-5的頁面的R位是101011,在下面第一個列圖中表示出來,表示在這段時間裡頁面0、2、4、5被訪問,下一個週期的訪問情況為110010,將前面的記錄情況向右平移一位,將最新的加到最前面。這樣五個週期下來,(e)圖表示了這五個週期裡這6個頁面被訪問的情況。

​ 如果把每個頁面的bit pattern當作一個二進位制數來看,這個數越大就說明這個頁面最近被訪問的越多,每次最近一個週期被訪問的情況被放到最前面,表示某次被訪問的情況是隨著時間的推移,它的權重也慢慢降低的。

The Working Set Page Replacement Algorithm

​ 工作集:一個程式當前正在使用的頁面的集合稱為它的工作集。設集合w(k,t),在任一時刻t,都存在一個集合w,它包含所有最近k次記憶體訪問所訪問的頁面。這個集合w(k,t)就叫工作集。

在這裡插入圖片描述

橫軸為k

​ 現在來看一個基於工作集的頁面替換演算法,基本思路就是:找出一個不在工作集中的頁面並替換掉它。

在這裡插入圖片描述

​ 掃描所有頁面檢查R位,如果為1,則說明這次缺頁中斷髮生的時候該頁面正在被使用,所以可以將上次使用的時間切換為當前的實際時間,這個頁面在當前的時鐘滴答週期中被訪問過,那麼它就應該出現在工作集中,並且不應該被刪除。

​ 如果R為0,且生存時間(即當前實際執行時間減去上次使用時間)大於x,那就說明已經有超過x的時間沒有使用這個頁面了,那它就不應該出現在工作集裡,所以將其移除。

​ 如果R為0,且生存時間小於x,那就說明x時間段內這個頁面至少使用過一次,但是要記錄生存時間最長的頁面,也就是“上次使用時間”最小的頁面,也就是站在現在這個時間使用最早的頁面。如果掃描完整個頁表卻沒有一個合適的被淘汰的頁面,那就淘汰生存時間最長的頁面。

WSClock Page Replacement Algorithm

​ 當缺頁中斷髮生後,需要掃描整個頁表才能確定淘汰的頁面,因此基本的工作集演算法是比較費時的。有一種基於時鐘演算法的改進演算法,並且使用了工作集資訊,成為WSClock(工作集時鐘)演算法。

​ 與時鐘演算法一樣,所需的資料結構是一個以頁框為元素的迴圈表。最初,該表是空的。當裝入第一個頁面後,把它加入到該表中。隨著更多的頁面的加入,他們形成一個環。每個表項包含來自基本工作集演算法的上次使用時間,以及R位(已標明)和M位(未標明)。

在這裡插入圖片描述

​ 與時鐘演算法一樣,每次缺頁中斷的時候,首先檢查指標指向的頁面。如果R位為1,則該頁面在當前的時鐘滴答中被使用過,則不適合淘汰,將其置0,指標指向下一個頁面。並重復該演算法。

​ 如果R=0,當頁面的生存時間大於x並且該頁面是乾淨的(乾淨,個人理解就是沒有修改過),他就不在工作集中,並且在磁碟上有一個有效的副本。申請此框,並把新頁面放在其中。如果此頁面被修改過就不能立即申請頁框,因為這個頁面在磁碟上沒有有效的副本。為了避免由於排程寫磁碟操作引起的程式切換,指標繼續向前走,演算法繼續對下一個頁面操作。比較,有可能存在一箇舊的且乾淨的頁面可以立即使用。

頁面置換演算法小結

演算法 註釋
最優演算法 不可實現,但可以用作基準
NRU(最近未使用)演算法 LRU的很粗糙的近似
FIFO(先進先出)演算法 可能拋棄重要頁面
第二次機會演算法 比FIFO有較大改善
時鐘演算法 現實的
LRU(最近最少使用)演算法 很優秀,但很難實現
NFU(最不經常使用)演算法 LRU的相對粗略的近似
老化演算法 非常近似LRU的有效演算法
工作集演算法 實現起來開銷很大
工作集時鐘演算法 好的有效演算法

Modeling Page Replacement algorithms

在這裡插入圖片描述

​ (a)圖是FIFO with 3 page frames

​ (b)圖是FIFO with 4 page frames

​ 如圖,橫軸上0、1、2、3、0、1、4、0、1、2、3、4是頁面的訪問順序,豎軸是已經存在的物理的頁,(a)圖中,先訪問第0頁,記憶體中沒有,所以產生缺頁中斷,最下面用P標識,類似於一個堆疊,每當訪問一個新的頁面就向下壓棧,訪問第1頁,記憶體中也沒有,向下壓棧,產生缺頁中斷,用P標識,以此類推,一致向下壓棧,最下面的會被擠出去......當8次訪問第0頁時,記憶體中已經存在第0頁,所以不會產生缺頁中斷。

​ (b)圖同理(a)圖,但不同的是b圖中有4個物理的頁,通過觀察發現,(a)圖中三個物理的頁產生了9次缺頁中斷,而(b)圖中4個物理的頁卻產生了10次缺頁中斷。事實並沒有像預想的一樣物理的頁越多產生的缺頁中斷越少。這就叫Belady's Anomaly。

​ 要避免Belady's Anomaly的產生,就要保證物理頁多的裡面放入的內容是物理頁少的裡面內容的超集(也就是物理頁少的裡面的內容是物理頁多的裡面的內容的子集),這樣,物理頁越多產生的缺頁就越少。圖中的FIFO演算法很明顯並不能保證這個前提。例如第8次訪問頁面a圖裡是4、1、0,b圖裡是0、4、3、2.

Stack Algorithm

​ 要保證上述的前提,引入了stack演算法

在這裡插入圖片描述

​ 前面的Reference string是訪問頁,下面的8個框是可以存放的堆疊頁,上面四個實框是真正的物理頁,每次訪問一個頁面的時候就往裡面壓棧,到第5次訪問第5頁的時候相當於把0從物理頁擠出去了,但還存在於堆疊頁中,當第8次訪問第3頁時,3還在裡面,就把堆疊中的3提前,不產生缺頁中斷,然後繼續類推,到第14次訪問第5頁的時候,5在堆疊頁中,但已經出了物理頁,所以會產生缺頁中斷,但還是同樣的將5提前,原來5上面的壓棧壓下去。下面的P表示產生了缺頁。Distance string表示的是當前訪問的頁在上次訪問記憶體後在堆疊中的第幾個,比如第14次訪問的第5頁,在第13次訪問完後,第5頁在5個,所以第14次的Distance string就等於5,如果上次訪問記憶體後堆疊頁中沒有這次訪問的頁就將Distance string等於無窮。

Probability density function

在這裡插入圖片描述

pdf表示概率密度函式,橫軸為distance string,縱軸表示等於這個distance string的有多少個

The Distance String

在這裡插入圖片描述

​ 用distance string計算頁面出錯率。左邊的C1就表示distance string等於1的有幾個,C2同理表示distance string等於2的有幾個。右邊的F1表示C2+C3+...+C無窮,同理F2 = C3+C4+...+C無窮。

​ 因此可以看出F1表示當有一個物理頁時候的缺頁次數,F2表示當有2個物理頁時候的缺頁次數。因為F1表示的是C2到C無窮的累加和,而C2又表示distance string=2時候的個數,distance string=2的就表示當前訪問的頁在堆疊頁的第二個,如果物理頁只有一個那就說明不在物理頁中,即會產生缺頁,C3、C4......C無窮類似。即Fx表示當有x個物理頁時候的缺頁次數。

Segmentation

分段和分頁的一些對比

在這裡插入圖片描述

Implementation of Pure Segmentation

在這裡插入圖片描述

Segmentation with Paging:MULTICS

​ 段頁式,在段裡分頁。前面分頁是一個程式一個頁表,現在這種分段是一個段一個頁表。

​ 段的描述字descriptor的結構如圖右所示,18個bit位的Main memory address of the page table,用來表示這個段的頁表在記憶體中的地址;9個bit位的Segment length表示段的長度,以頁為單位,就是這個段有多少個頁;1個bit位的Page size,表示頁的大小,1024個或64個words;還有表示段是否啟動分頁的位,如果沒啟動就是純分段,啟動了就是段頁式。

在這裡插入圖片描述

​ 上圖是一個34個bit位的虛擬地址,根據18個bit的段號去查表(就是上面的上面那個圖的最左邊那個表),找到段的頁表,根據後面6個bit的頁號,在頁表中找到具體的物理頁的位置(頁幀),最後根據10個bit的頁內偏移就可以找到真正的實體地址。

​ 為了加速查詢,同樣引入了TLB。

在這裡插入圖片描述

​ TLB中Segment number和Virtual page配合可以找到Page frame,Protection位表示讀寫許可權,Age表示老化程度,因為TLB中的項是有限的,當需要淘汰掉某些項的時候,就根據項的老化程度,越大說明在TLB中時間越久。is this entry used表示這個項在不在記憶體裡面。

相關文章