文章目錄
計算機如何工作?
將程序進入內存
這個程序必須從實際物理地址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
0x2240 % 0x1000(4K) == 0x2240 >> 12
,得到頁號,這一步是由 MMU 硬件完成。- 邏輯地址 :
0x02 : 0x240
,查頁表,頁表指針在PCB中 - 由頁號查到頁框號爲
3
,物理地址爲0x3240
多級頁表和快表
頁表的缺點:分頁小,會導致頁表太大
頁面尺寸爲 4K, 32位地址,4G內存會有 1M 的頁表項,需要佔用 4M內存,併發10個進程需要40M內存
如果頁表不連續,這種方式效率會很低,每執行一次指令都需要查找;如果頁表連續,則會造成浪費。
多級頁表
類似於書中的章和節,這樣遍歷時可以按章節跳過,而不是一頁一頁翻。
- 頁目錄有 個頁表指針,佔字節
- 每個頁表有個頁,頁表佔字節,指向了的空間。
- 我們看到圖中頁目錄用了三個頁表,那麼這個程序使用了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
時,首先p
爲0x300
,接着通過查 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 分區
總結
-
內存換入換出是虛擬內存實現的核心概念
-
虛擬內存是段頁實現的核心概念
-
段頁結構是一個程序執行的核心概念
-
一個程序的執行離不開進程的概念
-
內存管理機制名詞都是類似書中的:*段,頁,節(頁表),章(頁目錄表)
-
邏輯內存地址和物理內存地址的關係,更像是一本書的章節號和這本書的第幾個字的關係。
所以正常人找到書中一句話不會從頭開始數吧,效率太低了。怎麼說也要找到第幾章,第幾節,第幾頁,第幾段,這樣範圍大大縮小。 -
段是面向用戶,用戶直接面對的地址也是虛擬內存,方便管理。
-
頁是面向機器,分頁機制細度更高,因爲內存分配是不連續的,分頁機制解決降低內存使用率低下,效率更高。
-
段頁結合就需要虛擬內存概念的引入
-
虛擬內存會給進程一個連續的內存模型,但物理實現是離散的
-
當進程訪問某個虛擬地址的時候,就會先去看頁表,如果發現對應的數據不在物理內存上,就會發生缺頁異常
-
缺頁異常的處理過程,操作系統立即阻塞該進程,並將硬盤裏對應的頁換入內存,然後使該進程就緒,如果內存已經滿了,沒有空地方了,那就找一個頁覆蓋,至於具體覆蓋的哪個頁,就需要看操作系統的頁面置換算法是怎麼設計的了。