分段與分頁

張國星就是個弱智發表於2020-10-05
重定位

一個程式要加入到記憶體後才能開始執行,我們需要在記憶體中找一塊空閒區域來存放程式,那麼對於程式中所指明的地址,我們需要進行重定位操作,將邏輯實體地址轉化成實際的實體地址。
重定位的時機:

  1. 編譯時:需要在編譯時就知道哪些實體記憶體是空閒的(很不靈活),一般嵌入式系統可以用。
  2. 載入時:在程式載入到記憶體時改變程式中的地址,但是一旦載入到記憶體中就不能在動了,但是程式在載入後都會需要移動(swap交換)。
  3. 執行時重定位:每執行一條指令都從邏輯地址算出實體地址,每個程式的基地址都存放在PCB中,執行指令時第一步先從PCB中取出這個基地址,通過基地址+邏輯地址來進行地址翻譯。
分段

程式由若干個段組成:主程式,變數集,函式庫,動態陣列,棧,每個段有各自的特點以及用途,對於每個段來說其開始地址都是0,而不是把所有段組成一個段從0開始。這樣的話可以讓使用者獨立的考慮每個段(從程式設計師的角度來看)
因此我們可以不用將整個程式集中處理放到記憶體中,而是可以各段分別放入記憶體中(比如棧不夠時,分段處理可以只移動棧段的位置)。因此我們需要通過一個程式段表來儲存不同段對應的基址(作業系統對應的段表->GDT表)。每個程式都有各自的LDT表,LDT表也對應一個記憶體中的段,所以先從GDT表中找到LDT表,然後通過LDT表可以找到每個段的基址。
記憶體的分割:將程式分為多個段後,我們需要分割記憶體,將各個段放入記憶體中。

  1. 固定分割槽:作業系統初始化時將記憶體等分K個分割槽,因為段的大小有大有小,所以不太合適.
  2. 可變分割槽:用空閒分割槽表以及已分配分割槽表來進行管理,當一個段需要使用記憶體時,根據空閒分割槽表來給其分配記憶體。
    記憶體分段的問題:當沒有足夠大的空閒分割槽可分配時(記憶體碎片),需要進行空閒分割槽的合併,非常耗費時間,而且上層使用者此時是無法執行的。
分頁。

為了解決分段的問題,可以將實體記憶體等分成頁,針對每個段記憶體的請求,系統將一頁一頁的分配給這個段,此時一個段最多浪費一頁的空間。需要用一個頁表來儲存每個段的頁號所對應實體記憶體中的哪個頁框。
在這裡插入圖片描述
在這裡插入圖片描述

多級頁表

為了提高記憶體空間利用率,頁的大小應該儘可能的小,可是頁小了之後,頁表就會變大。
實際上大部分的邏輯地址是不會用到的,可是如果對於沒有使用的空間如果不在頁表中佔位,我們每次訪問地址都需要遍歷一遍頁表,效率太低。
我們可以使用多級頁表,將多個頁表組合成一個章節,每次查詢先找到所在章節,再找需要的頁表。對於不需要的章節在頁表中也進行佔位處理,不過節省了許多空間(因為不用每個頁都進行佔位,而是一個章佔一個位置)。

快表

多級頁表解決了空間儲存的問題,可增加了訪存的次數,我們使用快表來增加訪問速度,每次訪存先進行快表的訪問(速度非常快),如果沒查到再去多級頁表中進行查詢,並且更新快表內容。

段頁結合

從程式設計師的角度來看,程式是多個不同段組成的,而從實體記憶體來看,是希望把記憶體分成多個頁的。我們給每個程式的段分到虛擬記憶體中,建立虛擬記憶體到實體記憶體的對映來實現段頁結合(段面向使用者,頁面向硬體)。
從使用者角度來看,每個程式都有屬於他的一整塊空間,當進行訪問時,通過將虛擬地址轉化為實體地址來達成訪問。

載入過程:將記憶體分為多個相同長度的頁,將程式分成多個段,每一段都分成若干個頁對映到實體記憶體中,查詢資料時先通過段表找到虛擬地址,然後通過頁表找到對應的實體地址。
在這裡插入圖片描述

fork時的記憶體分配

根據不同的作業系統實現有不同的方法,下面只是其中一種可實現的方式。
我們首先假設每個程式的虛擬空間不相互重疊,在進行fork時,父子程式可以先公用同一實體記憶體,只需要建立子程式所需要的頁表關聯到同一實體記憶體。在有寫操作進行時子程式才進行實體記憶體的分配->寫時複製

記憶體換入換出

在使用者角度來看,其實際使用的是一大塊完整的空間,可是有時候實體記憶體是沒有那麼大的空間的,那麼在訪問時對未在實體記憶體中的資料需要從磁碟換入。
當請求資料時,根據邏輯地址(段號+偏移)查詢段表找到虛擬地址(頁號+偏移),再通過查頁表找到實際的實體地址,而有時候記憶體中是沒有該資料的,那麼此時就會產生一個缺頁中斷,執行頁錯誤處理程式,從記憶體中找到空閒物理頁,將資料從磁碟中讀入記憶體,修改頁表,這樣再次執行時便能夠成功找到該資料。
在這裡插入圖片描述
記憶體空間是有限的,當選擇頁面換入時,如果並不能獲得新的頁,就需要選擇一頁進行淘汰換出到磁碟。
比較常見的方法:FIFO,MIN演算法(將來最遠使用的頁淘汰),LRU演算法(將最近最長一段時間沒有使用的頁淘汰),Clock演算法。

相關文章