虛擬內存管理加拓展(全網最細)

寫在前面:我是【程序員寶藏】的寶藏派發員,致力於創作原創乾貨。我熱愛技術、熱愛開源與分享,創作的【計算機基礎面試問題】系列文章和【計算機基礎主幹知識】系列文章廣受好評!後期會創作更多優質原創系列文章!如果您對計算機基礎知識、編程等感興趣,可以關注我,我們一起成長!

本人力薦:如果覺得CSDN排版不夠美觀,歡迎來我的個人原創公zong號【程序員寶藏】(號如其名,誠不欺你!)查看有紅色重點標記和排版美觀的全系列文章(不細你來找我要紅包

好多同學問我要pdf版,我乾脆把全部文章都整理成了pdf直接打印版,在公zong號後臺回覆關鍵字【寶藏】即可免費帶回家慢慢看

覺得有收穫?希望老鐵們來個三連擊(點贊、評論、轉發),讓更多的人看到這篇文章!順便也激勵下我,嘿嘿!


相關係列文章:


1.前導知識簡述

【問】:爲什麼要進行內存管理?
答:在單道批處理系統階段,一個系統在一個時間段內只執行一個程序,內存的分配極其簡單,即僅分配給當前運行的進程。引入多道程序的併發執行後,進程之間共享的不僅僅是處理機,還有主存儲器。然而,共享主存會形成一些特殊的挑戰(越界、缺頁等)。若不對內存進行管理,則容易導致內存數據的混亂,以至於限制進程的併發執行。因此,爲了更好地支持多道程序併發執行,必須進行內存管理。

鏈接和裝入

創建進程首先要將程序和數據裝入內存。將用戶源程序變爲可在內存中執行的程序,通常需要以下幾個步驟:

  • 編譯。由編譯程序將用戶源代碼編譯成若干目標模塊。
  • 鏈接。由鏈接程序將編譯後形成的一組目標模塊及所需的庫函數鏈接在一起,形成一個完整的裝入模塊。
  • 裝入。由裝入程序將裝入模塊裝入內存運行。

程序的鏈接有以下三種方式:

  1. 靜態鏈接:程序運行前,先將各目標模塊及他們所需要的庫函數鏈接成一個完整的可執行程序,以後不再拆開。
  2. 裝入時動態鏈接:在裝入時,邊裝入邊鏈接。
  3. 運行時動態鏈接:對某些目標模塊的鏈接,是在程序執行中需要該目標模塊時才進行的。其優點是便於修改和更新,便於實現對目標模塊的共享。

程序的裝入有以下三種方式:

  1. 絕對裝入:單道程序環境下,邏輯地址和物理地址完全相同,不需要地址變換。
  2. 靜態重定位:裝入時一次性將邏輯地址轉換爲物理地址(重定位)
  3. 動態重定位:運行時才把邏輯地址轉換爲物理地址,適合程序在內存中會發生移動的情況。

【問】:覆蓋與交換?
答:覆蓋與交換技術是用來擴充內存的兩種方法。
覆蓋的【基本思想】如下:由於程序運行時並非任何時候都要訪問程序及數據的各個部分(尤其是大程序),因此可把用戶空間分成一個固定區和若干覆蓋區。將經常活躍的部分放在固定區,其餘部分按調用關係分段。首先將那些即將要訪問的段放入覆蓋區,其他段放在外存中,在需要調用前,系統再將其調入覆蓋區,替換覆蓋區中原有的段。覆蓋技術的特點是,打破了必須將一個進程的全部信息裝入主存後才能運行的限制,但當同時運行程序的代碼量大於主存時仍不能運行,此外,內存中能夠更新的地方只有覆蓋區的段,不在覆蓋區中的段會常駐內存。
交換(對換)的【基本思想】是,把處於等待狀態(或在CPU 調度原則下被剝奪運行權利)的程序從內存移到輔存,把內存空間騰出來,這一過程又稱換出;把準備好競爭CPU 運行的程序從輔存移到內存,這一過程又稱換入。中級調度採用的就是交換技術。
【區別】交換技術主要在不同進程(或作業)之間進行,而覆蓋則用於同一個程序或進程中。由於覆蓋技術要求給出程序段之間的覆蓋結構,使得其對用戶和程序員不透明,所以對於主存無法存放用戶程序的矛盾,現代操作系統是通過虛擬內存技術來解決的,覆蓋技術則已成爲歷史;而交換技術在現代操作系統中仍具有較強的生命力。

連續分配管理方式

  1. 單一連續分配
  2. 固定分區分配
  3. 動態分區分配

非連續分配方式

固定分區會產生內部碎片,動態分區會產生外部碎片,這兩種技術對內存的利用率都比較低。我們希望內存的使用能儘量避免碎片的產生,這就引入了分頁的思想:把主存空間劃分爲大小相等且固定的塊,塊相對較小,作爲主存的基本單位。每個進程也以塊爲單位進行劃分,進程在執行時,以塊爲單位逐個申請主存中的塊空間。

  1. 基本分頁存儲管理方式
  2. 基本分段存儲管理方式
  3. 基本段頁式管理方式

2.頁式虛擬內存

基於局部性原理,在程序裝入時,將程序的一部分裝入內存,而將其餘部分留在外存,就可
啓動程序執行。在程序執行過程中,當所訪問的信息不在內存時,由操作系統將所需要的部分調入內存,然後繼續執行程序。另一方面,操作系統將內存中暫時不使用的內容換出到外存上,從而騰出空間存放將要調入內存的信息。這樣,系統好像爲用戶提供了一個比實際內存大得多的存儲器,稱爲虛擬存儲器。

【局部性原理】:快表、頁高速緩存及虛擬內存技術從廣義上講,都屬於高速緩存技術。這個技術所依賴的原理就是局部性原理。
局部性原理表現在以下兩個方面:1) 時間局部性。程序中的某條指令一旦執行,不久後該指令可能再次執行;某數據被訪問過,不久後該數據可能再次被訪問。產生時間局部性的典型原因是程序中存在着大量的循環操作。2) 空間局部性。一旦程序訪問了某個存儲單元,在不久後,其附近的存儲單元也將被訪問,即程序在一段時間內所訪問的地址,可能集中在一定的範圍之內,因爲指令通常是順序存放、順序執行的,數據也一般是以向量、數組、表等形式簇聚存儲的。
時間局部性通過將近來使用的指令和數據保存到高速緩衝存儲器中,並使用高速緩存的層次
結構實現。空間局部性通常使用較大的高速緩存,並將預取機制集成到高速緩存控制邏輯中實現。虛擬內存技術實際上建立了“內存-外存”的兩級存儲器結構,利用局部性原理實現高速緩存。

請求分頁系統建立在基本分頁系統基礎之上,爲了支持虛擬存儲器功能而增加了請求調頁功能和頁面置換功能。請求分頁是目前最常用的一種實現虛擬存儲器的方法。

爲了實現請求分頁,系統必須提供一定的硬件支持。除了需要一定容量的內存及外存的計算
機系統,還需要有頁表機制、缺頁中斷機構和地址變換機構。

頁表機制

請求分頁系統的頁表機制不同於基本分頁系統,請求分頁系統在一個作業運行之前不要求全部一次性調入內存,因此在作業的運行過程中,必然會出現要訪問的頁面不在內存中的情況,如何發現和處理這種情況是請求分頁系統必須解決的兩個基本問題。爲此,在請求頁表項中增加了4 個字段,如圖所示:

缺頁中斷機構

在請求分頁系統中,匈當所要訪問的頁面不在內存中時,便產生一個缺頁中斷,請求操作系
統將所缺的頁調入內存。此時應將缺頁的進程阻塞(調頁完成喚醒),若內存中有空閒塊,則分配一個塊,將要調入的頁裝入該塊,並修改頁表中的相應頁表項,若此時內存中沒有空閒塊,則要淘汰某頁(若被淘汰頁在內存期間被修改過,則要將其寫回外存)。

【注意】:缺頁中斷作爲中斷,同樣要經歷諸如保護CPU 環境、分析中斷原因、轉入缺頁中斷處理程序、恢復CPU 環境等幾個步驟。但與一般的中斷相比,它有以下兩個明顯的【區別】:
1)在指令執行期間而非一條指令執行完後產生和處理中斷信號,屬於內部中斷。
2)一條指令在執行期間,可能產生多次缺頁中斷。

地址變換機構

一張流程圖一目瞭然:

頁面置換算法
  1. 最佳(OPT) 置換算法

最佳(Optimal, 0PT) 置換算法選擇的被淘汰頁面是以後永不使用的頁面,或是在最長時間內不再被訪問的頁面,以便保證獲得最低的缺頁率。然而,由於人們目前無法預知進程在內存下的若干頁面中哪個是未來最長時間內不再被訪問的,因而該算法無法實現。

  1. 先進先出(FIFO) 頁面置換算法

優先淘汰最早進入內存的頁面,即在內存中駐留時間最久的頁面。該算法實現簡單,只需把
調入內存的頁面根據先後次序鏈接成隊列,設置一個指針總指向最早的頁面。但該算法與進程實際運行時的規律不適應,因爲在進程中,有的頁面經常被訪問。

FIFO 算法還會產生所分配的物理塊數增大而頁故障數不減反增的異常現象,稱爲Belady 異常。只有FIFO 算法可能出現Belady 異常, LRU 和OPT 算法永遠不會出現Belady 異常。

  1. 最近最久未使用(LRU)置換算法

選擇最近最長時間未訪問過的頁面予以淘汰,它認爲過去一段時間內未訪問過的頁面,在最
近的將來可能也不會被訪問。該算法爲每個頁面設置一個訪問字段,來記錄頁面自上次被訪問以來所經歷的時間,淘汰頁面時選擇現有頁面中值最大的予以淘汰。

LRU 算法的性能較好,但需要寄存器和棧的硬件支持。LRU 是堆棧類的算法。理論上可以
證明,堆棧類算法不可能出現Belady 異常。FIFO 算法基於隊列實現,不是堆棧類算法。

  1. 時鐘(CLOCK) 置換算法

簡單的CLOCK 算法給每幀關聯一個附加位,稱爲使用位。當某頁首次裝入主存時,將該幀
的使用位設置爲1; 當該頁隨後再被訪問到時,其使用位也被置爲1 。對於頁替換算法,用於替換的候選幀集合可視爲一個循環緩衝區,並有一個指針與之相關聯。當某一頁被替換時,該指針被設置成指向緩衝區中的下一幀。當需要替換一頁時,操作系統掃描緩衝區,以查找使用位被置爲0 的一幀。每當遇到一個使用位爲1 的幀時,操作系統就將該位重新置爲0; 若在這個過程開始時,緩衝區中所有幀的使用位均爲0, 則選擇遇到的第一個幀替換;若所有幀的使用位均爲1,則指針在緩衝區中完整地循環一週,把所有使用位都置爲0, 並停留在最初的位置上,替換該幀中的頁。由於該算法循環檢查各頁面的情況,因此稱CLOCK算法,又稱最近未用(Not Recently
Used, NRU) 算法。

在使用位的基礎上再增加一個修改位,則得到改進型CLOCK 置換算法。這樣,每幀都處於以下4種情況之一:
1)最近未被訪問,也未被修改(u= 0, m = 0) 。
2)最近被訪問,但未被修改(u=l,m=0) 。
3)最近未被訪問,但被修改(u=0,m= 1) 。
4)最近被訪問,被修改(u=l,m=l)

算法執行步驟如下:

  1. 從指針的當前位置開始,掃描幀緩衝區。在這次掃描過程中,對使用位不做任何修改。選擇遇到的第一個幀(u = 0, m = 0) 用於替換。
  2. 若第1) 步失敗,則重新掃描,查找(u=0,m= 1) 的幀。選擇遇到的第一個這樣的幀用於替換。在這個掃描過程中,對每個跳過的幀,把它的使用位設置成0 。
  3. 若第2) 步失敗,則指針將回到它的最初位置,且集合中所有幀的使用位均爲0 。重複第
  4. 步,並且若有必要,重複第2) 步,以便可以找到供替換的幀。

【注意】:改進型CLOCK 算法優於簡單CLOCK 算法的地方在於替換時首選沒有變化的頁。由於修改過的頁在被替換之前必須寫回,因而這樣做會節省時間。

【抖動】:在頁面置換過程中,一種最糟糕的情形是,剛剛換出的頁面馬上又要換入主存,剛剛換入的頁面馬上又要換出主存,這種頻繁的頁面調度行爲稱爲抖動或顛簸。若一個進程在換頁上用的時間多於執行時間,則這個進程就在顛簸。頻繁發生缺頁中斷(抖動)的主要原因是,某個進程頻繁訪問的頁面數目高於可用的物理頁幀數目。

虛擬內存是怎麼解決問題的?會帶來什麼問題?
答:虛擬內存使用外存上的空間來擴充內存空間,通過一定的換入/換出,使得整個系統在邏輯上能夠使用一個遠遠超出其物理內存大小的內存容量。因爲虛擬內存技術調換頁面時需要訪問外存,會導致平均訪存時間增加,若使用了不合適的替換算法,則會大大降低系統性能。

【問】:多級頁表解決了什麼問題?又會帶來什麼問題?
答:多級頁表解決了當邏輯地址空間過大時,頁表的長度會大大增加的問題。多級頁表是爲了節省空間。(單級頁表爲了隨機訪問必須連續存儲,如果虛擬內存空間很大,就需要很多頁表項,就需要很大的連續內存空間【你能想象頁表比分配的頁(“運行頁”)還多嗎?】;但是多級頁表不需要,最開始只需一頁。)
【問題】:而採用多級頁表時,一次訪盤需要多次訪問內存甚至磁盤,會大大增加一次訪存的時間。

3.段式虛擬內存

段式虛擬存儲器中的段是按程序的邏輯結構劃分的,各個段的長度因程序而異。把虛擬地址
分爲兩部分:段號和段內地址。虛擬地址到實地址之間的變換是由段表來實現的。段表是程序的邏輯段和在主存中存放位置的對照表。段表的每行記錄與某個段對應的段號、裝入位、段起點和段長等信息。由於段的長度可變,所以段表中要給出各段的起始地址與段的長度。

段式虛擬存儲器的優點是,段的分界與程序的自然分界相對應,因而具有邏輯獨立性,使得它易於編譯、管理、修改和保護,也便於多道程序的共享;缺點是因爲段長度可變,分配空
間不便,容易在段間留下碎片,不好利用,造成浪費。

4.段頁式虛擬內存

把程序按邏輯結構分段,每段再劃分爲固定大小的頁,主存空間也劃分爲大小相等的頁,程
序對主存的調入、調出仍以頁爲基本傳送單位,這樣的虛擬存儲器稱爲段頁式虛擬存儲器。在段頁式虛擬存儲器中,每個程序對應一個段表,每段對應一個頁表,段的長度必須是頁長的整數倍,段的起點必須是某一頁的起點。

虛地址分爲段號、段內頁號、頁內地址三部分。CPU 根據虛地址訪存時,首先根據段號得到段表地址;然後從段表中取出該段的頁表起始地址,與虛地址段內頁號合成,得到頁表地址;最後從頁表中取出實頁號,與頁內地址拼接形成主存實地址。

段頁式虛擬存儲器的優點是,兼具頁式和段式虛擬存儲器的優點,可以按段實現共享和保護。缺點是在地址變換過程中需要兩次查表,系統開銷較大。


不要忘記去我的個人原創公zong號【程序員寶藏】----專注於計算機基礎、編程、分享,獲取【寶藏】哦!
在這裏插入圖片描述

作爲過來人,有考研的小夥伴可以加我好友(公zong號有二維碼,備註【考研】),免費解答相關問題,做你的知心大哥哥!我們一研爲定


覺得有收穫?希望老鐵們來個三連擊(點贊、評論、轉發),讓更多的人看到這篇文章!順便也激勵下我,嘿嘿!

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