內存管理兩部曲之虛擬內存管理

傳統存儲管理存在的問題

虛擬內存這個東西他爲何會出現?他出現的背景是什麼?git

前文 內存管理兩部曲之物理內存管理 提到:隨着用戶程序功能的增長,進程所須要的內存空間愈來愈大,進程空間很容易就突破了物理內存的實際大小,致使進程沒法運行。web

所以,爲了解決內存不足的狀況,緩和大程序與小內存之間的矛盾,擴充內存容量勢在必行。算法

能夠從物理和邏輯兩方面來考慮擴充內存容量,物理擴容沒啥技術含量,須要咱們研究的天然是如何從邏輯上擴充內存容量。緩存

所謂邏輯擴充,就是說實際上物理內存的容量沒有發生改變,可是它能裝的東西卻變多了,使得用戶看來彷佛有一個比實際內存大得多的內存。微信

對內存的邏輯擴充技術主要有三種:覆蓋技術、交換技術、以及虛擬內存(Virtual Memory),也稱爲虛擬存儲器。事實上,這些邏輯擴充技術的核心理念都是一致的,研究的都是將哪一個進程(或進程的某部分)暫時從內存移到外存(磁盤),以騰出內存空間供其餘進程(或進程的某部分)佔用。app

覆蓋(Overlay)和交換(Swapping)這兩種存在於早期操做系統中的邏輯擴充技術如今已經成爲歷史,這裏就簡單介紹下:編輯器

前文說過,早期操做系統僅將內存空間分紅兩塊:系統區(用於存放操做系統相關數據)和用戶區(用於存放用戶進程相關數據,內存中只能有一道用戶程序,用戶程序獨佔整個用戶區空間,顯然,內存空間容不下某個用戶程序的現象常會發生。學習

覆蓋技術(Overlay)的基本思想就是:程序運行時並不是任什麼時候候都要訪問程序及數據的全部部分(尤爲是大程序),所以能夠把用戶空間(內存)分紅一個固定區和一個或多個覆蓋區。flex

將程序常常活躍的部分放在固定區,其他部分按調用關係進行分段:首先將那些即將要用的段放在覆蓋區,其餘段放在外存(磁盤),在須要調用前由用戶來安排特定的系統調用將這些放在外存中的段調入覆蓋區,替換覆蓋區中原有的段。url

覆蓋技術的缺點顯而易見而且能夠說是讓人沒法接受的,那就是覆蓋技術是把解決內存空間不足的問題交給了用戶。操做系統僅僅爲用戶提供將覆蓋段調入內存的系統調用,可是必須由用戶本身來講明覆蓋哪一個段、調入哪一個段。

合着我用個電腦還得算着怎麼才能讓個人程序不崩潰?

OK,能夠看出來,覆蓋技術實際上是用在同一個做業/進程的不一樣段之間的,那麼不一樣的做業/進程之間怎麼辦呢?

這就是交換技術的適用場景。

交換技術(Swapping)的基本思想是:空閒進程/做業主要存儲在外存(磁盤)上,當其中某個進程/做業須要運行的時候,就將其從磁盤中完整地調入內存,使該進程運行一段時間,而後再把它返回磁盤。因此說當進程/做業不運行的時候它們是不會佔用內存的。


事實上,覆蓋和交換技術分別解決了傳統存儲管理(物理內存管理)中存在的某個問題:

  • 覆蓋技術打破了 做業/進程必須一次性所有裝入內存後才能開始運行(一次性)的限制
  • 交換技術打破了 一旦做業被裝入內存,就會一直駐留在內存中,直至做業運行結束(駐留性)的限制

固然了,Anyway,這兩種邏輯擴充技術已經成爲歷史,虛擬內存技術纔是目前的主流,它綜合了這兩種古老技術的特色,單槍匹馬解決了傳統存儲管理中存在的這兩個問題。

什麼是虛擬內存

有了上述交換技術的鋪墊,理解起虛擬內存來也就不那麼陌生了。

固然了,在此以前,我必定要着重聲明的是,不要把虛擬內存看成一個實際存在的東西,它是一門技術!和交換技術覆蓋技術同樣是一門用來邏輯擴充內存空間的技術!

虛擬內存技術基於一個很是重要的原理,局部性原理

1)時間局部性:若是執行了程序中的某條指令,那麼不久後這條指令頗有可能再次執行;若是某個數據被訪問過,不久以後該數據極可能再次被訪問。(由於程序中存在大量的循環)

2)空間局部性:一旦程序訪問了某個存儲單元,在不久以後,其附近的存儲單元也頗有可能被訪問(由於不少數據在內存中都是連續存放的,而且程序的指令也是順序地在內存中存放的)

基於這個局部性原理,在一個程序裝入內存的時候,能夠只將這個程序中很快會用到的部分裝入內存,暫時用不到的部分仍然留在外存(磁盤),而且程序能夠正常執行;

而在程序執行過程當中,當 CPU 所須要的信息不在內存中的時候,由操做系統負責將所需信息從外存(磁盤)調入內存,而後繼續執行程序;

若是調入內存的時候內存空間不夠,由操做系統負責將內存中暫時用不到的信息換出到外存。

以上,就是虛擬內存技術。

如何實現虛擬內存技術

能夠看見,虛擬內存容許一個做業/進程分屢次調入內存,那若是採用連續分配方式,不方便實現,因此虛擬內存技術的實現是創建在不連續分配管理方式之上的。

傳統的基本分頁管理、基本分段管理、基本段頁式管理和虛擬內存技術結合,分別稱爲請求分頁管理(頁式虛存系統)、請求分段管理(段式虛存系統)、請求段頁式管理(段頁式虛存系統)。

這幾個概念很是容易混淆,其實很容易區分,記住這句話就 OK,摘自百度百科:

若是不具有請求調頁、頁面置換的功能,則稱爲基本分頁管理(或稱爲純分頁管理),它不具備支持實現虛擬內存的功能,它要求把每一個做業(進程)所有裝入內存後方能運行。

請求分段存儲管理也差很少,它創建在分段存儲管理之上,但增長了請求調段、段置換功能。

請求調頁、頁面置換 和 請求調段、段置換概念差很少,這裏以請求調頁和頁面置換爲例解釋下。

  • 在程序執行過程當中,當所訪問的信息不在內存時,由操做系統負責將所需信息從外存(磁盤)調入內存,而後繼續執行程序(操做系統要提供 請求調頁的功能, 將內存中缺失的頁面從磁盤調入內存 );
  • 若內存空間不夠,由操做系統負責將內存中暫時用不到的信息換出到磁盤(操做系統要提供 頁面置換的功能, 將暫時用不到的頁面換出磁盤)。

具體來講,在頁式虛存系統中,每當 CPU 要訪問的頁面不在內存時,就會產生一個缺頁中斷,而後由操做系統的缺頁中斷處理程序來處理中斷。此時,缺頁的這個進程/做業就會被阻塞住,放入阻塞隊列,調頁完成後再將其喚醒,放回就緒隊列。

  • 若是內存中有空閒塊,則爲該進程分配一個空閒塊,將所缺的頁面裝入這個塊中,並修改頁表中相應的頁表項。
  • 若是內存中沒有空閒塊,則由頁面置換算法選擇一個頁面淘汰,若該頁面在內存期間被修改過,則要將其寫回外存,未修改過的頁面不用寫回外存。

能夠看出來,這並非一個簡單的過程,基本分頁管理中的簡單頁表已經沒法勝任這樣的工做。

咱們仍是先來回顧下基本分頁管理的頁表,它只有頁號和塊號兩個字段:

請求分頁管理的頁表天然是會複雜很多的:

1)爲了實現 「請求調頁」 功能,操做系統須要知道每一個頁面是否已經調入內存,若是還沒調入,那麼也須要知道該頁面在磁盤中存放的位置。

2)而當內存空間不夠時,要實現 「頁面置換」 功能,操做系統須要經過某些指標來決定到底換出哪一個頁面,有的頁面沒有被修改過,就不用浪費時間寫回磁盤;有的頁面修改過,就須要將磁盤中的舊數據覆蓋。所以,操做系統也須要記錄各個頁面是否被修改的信息。

爲此,請求分頁管理的頁表中添加了 4 個字段:

  • 狀態位:該頁面是否已調入內存
  • 訪問字段:可記錄該頁面最近被訪問過幾回,或記錄上次訪問該頁面的時間,供頁面置換算法換出頁面時參考
  • 修改位:該頁面調入內存後是否被修改過
  • 外存地址:該頁面在外存中的存放地址

頁面置換算法也是一個很重要的內容,原本應該在這篇文章裏一塊兒寫的,But 想到 「頁面置換」 問題不只僅是在虛擬內存中存在,在計算機設計的其餘領域也會一樣發生(好比多數計算機都會把最近使用過的 32 字節或者 64 字節存儲塊保存在一個或多個高速緩存中,當這些高速緩存存滿後就必須選取一些塊丟棄掉,以此來存入最新的使用過的存儲塊),因此決定後續單開一篇文章。




  • 博主小碩在讀,深耕 Java,目前在維護一個教程類倉庫 CS-Wiki 「Gitee 官方推薦項目,現已 1.7k+ star,倉庫地址:https://gitee.com/veal98/CS-Wiki」,公衆號上的文章也會在此同步更新,歡迎各位前來交流學習。
  • 準備春招秋招的小夥伴能夠參考個人這個論壇項目 Echo 「Gitee 官方推薦項目,現已 800+ star,倉庫地址:https://gitee.com/veal98/Echo」。配套教程正在同步更新中,公衆號後臺回覆 "Echo" 便可免費獲取。
  • 另外,雖然如今本號仍然很小,不過我仍是建了一個交流羣『 小牛肉和它的小夥伴們 』,感興趣的各位能夠下方掃碼加我微信回覆 "進羣",我拉你進羣:

本文分享自微信公衆號 - 飛天小牛肉(CS-Wiki)。
若有侵權,請聯繫 support@oschina.cn 刪除。
本文參與「OSC源創計劃」,歡迎正在閱讀的你也加入,一塊兒分享。

相關文章
相關標籤/搜索