內存管理(哈工大李志軍)

計算機如何工作?

在這裏插入圖片描述

將程序進入內存

在這裏插入圖片描述
這個程序必須從實際物理地址0開始纔可執行。

重定位:修改程序中的地址(相對地址)

在這裏插入圖片描述
相當於加入了基址。

什麼時候完成重定位?

  • 編譯時:編譯時重定位得程序只能放在內存固定位置
  • 載入時:重定位的程序一旦載入內存就不能動了
  • 運行時

交換:程序載入後移動

在這裏插入圖片描述

運行時重定位

在這裏插入圖片描述
在這裏插入圖片描述

  • 首先程序編譯完成,執行:
  • 創建進程1和進程2,各找到一段空閒內存,並把各地址作爲 base 賦給各進程的PCB
  • 程序載入到 base 爲基址的內存
  • 進程1 switch_to 切換到進程2,要將基地址更改爲進程2 PCB 中的base
    在這裏插入圖片描述

內存分段

在這裏插入圖片描述
在這裏插入圖片描述
GDT 是全局描述符表,只有一個
進程切換時查LDT (局部描述符表),LDT 在 進程的PCB 中
在這裏插入圖片描述

內存分區

在這裏插入圖片描述
在這裏插入圖片描述
在這裏插入圖片描述
在這裏插入圖片描述

此時再次申請 reqSize = 40K,選擇哪一個?
在這裏插入圖片描述

  • 首先適配:分割最先遇到符合大小的分區,速度快
  • 最佳適配:每次都分割最接近的,會剩下更小的空閒分區,形成內存碎片。
  • 最差適配:分割最大的分區,最後得到較爲均勻的分區
    在這裏插入圖片描述
    答案是 B

分頁

可變分區的問題:
在這裏插入圖片描述
在這裏插入圖片描述
將內存分割固定大小的頁,像麪包切片一樣,假設頁大小爲 4K ,程序請求內存按頁分配,那麼最多浪費不超過4K。

在這裏插入圖片描述
mov [0x2240],%eax

  1. 0x2240 % 0x1000(4K) == 0x2240 >> 12 ,得到頁號,這一步是由 MMU 硬件完成。
  2. 邏輯地址 :0x02 : 0x240 ,查頁表,頁表指針在PCB中
  3. 由頁號查到頁框號爲3,物理地址爲0x3240

多級頁表和快表

頁表的缺點:分頁小,會導致頁表太大
頁面尺寸爲 4K, 32位地址,4G內存會有 1M 的頁表項,需要佔用 4M內存,併發10個進程需要40M內存
在這裏插入圖片描述

在這裏插入圖片描述
如果頁表不連續,這種方式效率會很低,每執行一次指令都需要查找;如果頁表連續,則會造成浪費。

多級頁表

在這裏插入圖片描述
類似於書中的章和節,這樣遍歷時可以按章節跳過,而不是一頁一頁翻。

  • 頁目錄有 2102^{10}個頁表指針,佔2104=4K2^{10} * 4 = 4K字節
  • 每個頁表有2102^{10}個頁,頁表佔2104=4K2^{10} * 4 = 4K字節,指向了2102104=4M2^{10}*2^{10} * 4 = 4M的空間。
  • 我們看到圖中頁目錄用了三個頁表,那麼這個程序使用了12M內存。
  • 考慮這個機制和之前單頁表的佔用對比:頁目錄佔用 4K,而頁表不需要都駐留內存,這個程序使用了三個頁表,共12K,總共佔用4K + 12K= 16K的內存,遠小於單頁表情況下的4M的內存。
  • linux 0.11 中:

在這裏插入圖片描述

快表

在這裏插入圖片描述
在32位系統上,使用多級頁表會增加一次訪存,但在64位系統上,使用多級頁表會導致增加多次訪存。
在這裏插入圖片描述
在這裏插入圖片描述

段頁結合的實際內存管理

在這裏插入圖片描述
爲了將分段機制和分頁機制結合起來,引入了虛擬內存的概念。
用戶側爲分段機制,物理側做分頁機制

在這裏插入圖片描述

實際的段頁式內存管理

在這裏插入圖片描述
在這裏插入圖片描述
1. 首先將虛擬內存分割出一塊區域作爲用戶的代碼段、數據段,可以使用分區方法。
在這裏插入圖片描述
2. 將虛擬內存中的段分割,與物理內存的頁做關聯。

在這裏插入圖片描述
3. 執行mov [300],首先查段表找到虛擬基址0x45000,並得到虛擬地址0x45300
在這裏插入圖片描述
4. 查頁表第 0x45 項,得到頁框號7,得到物理基址0x7000
5. 得到物理地址0x7300
在這裏插入圖片描述
fork( ):
在這裏插入圖片描述
copy_mem()分配虛擬內存,設置段表,參數p爲進程的 PCB,new_data_base = nr * 0x4000000相當於對內存做了分割,每個進程佔用64M虛擬地址空間,接下來兩行完成了對段表的填寫。
在這裏插入圖片描述

分配內存(跳過),建頁表:
在這裏插入圖片描述
copy_page_tables參數爲虛擬地址,from_dir是父進程的虛擬地址
在這裏插入圖片描述
在這裏插入圖片描述
在這裏插入圖片描述
在這裏插入圖片描述

在這裏插入圖片描述

  • 進程1 是 進程2 的父進程,但映射的已經不是同一地址了。
  • 當執行 *p = 7時,首先 p0x300 ,接着通過查 LDT 中的段表得到虛擬地址 0x00400300,虛擬地址再通過頁表找到物理內存。

內存換入

在這裏插入圖片描述
在這裏插入圖片描述
在這裏插入圖片描述

  • 執行load [addr],當缺頁時,產生中斷,啓動頁錯誤處理程序,從磁盤中讀入到一空閒頁中,並做好頁表和物理內存的映射,並重新執行load [addr],MMU會使PC保持不動而不是PC+ 1執行下一指令。
    在這裏插入圖片描述
    答案是 C

實際系統的請求調頁

在這裏插入圖片描述
系統初始化時就已經設置好中斷處理。
在這裏插入圖片描述
中斷髮生,保護現場所以有一堆push,最後一行將頁錯誤線性地址作爲參數壓入棧,調用 do_no_page()
在這裏插入圖片描述
申請一個空頁,並從磁盤中讀入,調用put_page(page,address)建立映射。
在這裏插入圖片描述

內存換出

內存換入時,會調用get_free_page()來取得新的空頁,可內存是有限的,怎麼處理?
在這裏插入圖片描述

FIFO 頁面置換

在這裏插入圖片描述

MIN 頁面置換

選最遠將使用的頁淘汰,是最優方案
在這裏插入圖片描述

LRU 頁面置換

選最近最長一段時間沒有使用的頁淘汰(最近最少使用)
在這裏插入圖片描述
在這裏插入圖片描述
在這裏插入圖片描述
在這裏插入圖片描述

  • 每次訪問一頁時,自動設置爲 1
  • 當選擇淘汰頁時,掃描該位,如果是 1 則清 0(再給一次機會),並繼續掃描,是0時淘汰該頁。
    在這裏插入圖片描述
  • 如果缺頁很少,很有可能所有的 R 都會被置爲 1 ,如果再發生缺頁,將會轉完一圈再淘汰當前頁,退化爲 FIFO
  • 定時清除R位,放入時間中斷中,慢指針放入到選擇淘汰中。

在這裏插入圖片描述
紅框內是顛簸原因的解釋,優化此問題需要 工作集 概念的引入

內存換入換出總結

Linux 中的 swap 分區
在這裏插入圖片描述

總結

  • 內存換入換出是虛擬內存實現的核心概念

  • 虛擬內存是段頁實現的核心概念

  • 段頁結構是一個程序執行的核心概念

  • 一個程序的執行離不開進程的概念

  • 內存管理機制名詞都是類似書中的:*段,頁,節(頁表),章(頁目錄表)

  • 邏輯內存地址和物理內存地址的關係,更像是一本書的章節號和這本書的第幾個字的關係。
    所以正常人找到書中一句話不會從頭開始數吧,效率太低了。怎麼說也要找到第幾章,第幾節,第幾頁,第幾段,這樣範圍大大縮小。

  • 段是面向用戶,用戶直接面對的地址也是虛擬內存,方便管理。

  • 頁是面向機器,分頁機制細度更高,因爲內存分配是不連續的,分頁機制解決降低內存使用率低下,效率更高。

  • 段頁結合就需要虛擬內存概念的引入

  • 虛擬內存會給進程一個連續的內存模型,但物理實現是離散的

  • 當進程訪問某個虛擬地址的時候,就會先去看頁表,如果發現對應的數據不在物理內存上,就會發生缺頁異常

  • 缺頁異常的處理過程,操作系統立即阻塞該進程,並將硬盤裏對應的頁換入內存,然後使該進程就緒,如果內存已經滿了,沒有空地方了,那就找一個頁覆蓋,至於具體覆蓋的哪個頁,就需要看操作系統的頁面置換算法是怎麼設計的了。

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章