虛擬記憶體

来源:https://www.cnblogs.com/HopeGi/archive/2018/09/03/9577968.html
-Advertisement-
Play Games

在正式講述虛擬記憶體之前需要提及存儲器的層級結構以及進程在記憶體中的結構。 存儲器的層級結構速度從快到慢排列如下 寄存器——L1高速緩存——L2高速緩存——L3高速緩存——主存——磁碟——分散式文件系統 而成本也是從高到低,空間是從低到高。 兩個相鄰的存儲設備,前者往往是充當後者的高速緩存,後者往往存儲 ...


在正式講述虛擬記憶體之前需要提及存儲器的層級結構以及進程在記憶體中的結構。

存儲器的層級結構速度從快到慢排列如下

寄存器——L1高速緩存——L2高速緩存——L3高速緩存——主存——磁碟——分散式文件系統

而成本也是從高到低,空間是從低到高。

兩個相鄰的存儲設備,前者往往是充當後者的高速緩存,後者往往存儲比前者更完整的數據。

後面的內容會涉及到高速緩存和主存。

   

   

為了簡單的理解可以假設主存是一個線性的數組。每個元素可以是一個位元組。而主存與硬碟或者與高速緩存間做數據傳輸時,每次可以傳輸若幹個位元組,我們可以把這若幹個位元組定為一個新的單位,叫"塊"。而高速緩存中每個存儲的元素則是一個塊。高速緩存的存儲結構

如上圖所示,高速緩存被分成S個組,每個組裡面有E行,每行都有一個有效位,t個標記為和B個位元組,這B個位元組就組成了之前提到的塊。並且和記憶體地址有這樣的一個關係m=t+s+b。即有t個標記位,s個位作為組索引,b個位作為塊偏移,並且是t,s,b是從高位到低位排列。這個關係決定了給定一個地址,它該存放在高速緩存中的哪個位置。

   

另外整個高速緩存的總容量是C=S*B*E;按照S和B的變換可以把高速緩存分成下麵三種類型

1.直接映射

2.組相聯

3.全相聯

直接映射和全相聯是兩種極端情況。

直接映射是緩存中每個組只有1行,即E=1。對於這種情況,當某個當某個地址在緩存中發生衝突時則直接替換。

全相聯是緩存中只有一個組,所有行都在這個唯一的組裡面,相當於S=1。這種情況所有緩存都放在一個組裡面,然後輪詢找出哪一行是未使用的,如果全部組都已經使用了,那就按照一定的演算法找出一個塊踢出,再放上新的塊。

組相連則是介於上面兩種情況,每個組最少有兩行。這種情況跟全相聯一樣,不命中的時候在組裡面找不到未使用的塊,也是需要有策略選出一個犧牲的塊,替換上新的。

下麵則用直接映射來模擬一下讀取高速緩存的過程

現在有一個直接映射的高速緩存如下

SEBm=4124

由此可以得出s=2,b=1,t=m-b-s=4-1-2=1,整個地址構成如下

t=1

s=2

b=1

所有地址的標記位,組索引和塊偏移如下表所示,另外給記憶體中的塊編上一個序號

高速緩存如下

假設現在讀地址0的字,按照上面的表,組塊索引是0,標記位是0,緩存不命中,需要從記憶體中讀取塊0寫入高速緩存,因此m[0]和m[1]會被寫入組0,標記位是0,有效位置1,寫後高速緩存如下

接著讀地址1的字,記憶體地址是0001,組索引為0,標記位是0,查找高速緩存,組號和標記位對上,有效位是1,取偏移是1的值m[1]

接下來讀地址8的字,記憶體地址是1001,組索引是0,標記位是1,查找高速緩存不命中,而且該組已經被用上了,犧牲了原本的0組的兩個值m[0]和m[1],讀取新的值m[8]和m[9],塊偏移是1,取值m[8]

假設再讀地址0的字時,又會發現不命中,重覆類似第一次讀地址0的操作。

   

接下來補充鏈接的少部分的內容,這些內容會在記憶體映射和記憶體分配的時候會涉及到

上面的這幅圖在眾多C語言的書都有出現,其他語言的都有類似的流程圖。一個C文件經過預處理和編譯,得出了一份彙編語言的源碼文件。這個文件經過彙編器彙編之後,就產生了人類無法直接閱讀的可重定向目標文件。這個文件具有一定的結構,

它會把原本程式員寫的源代碼拆分成若幹部分:指令放到.text節;全局靜態變數放到.data節;內部定義的函數名、引用外部函數名這些符號信息放到.symtab節……但是外部引用的函數地址(如我們最常用的printf)在這個階段還是沒有的,

   

這些需要引用地址的信息都放到一個叫"可重定向條目"的結構裡面,此時需要往下走到鏈接這個過程。

最後鏈接器鏈接時會把這些外部引用的函數地址給填上去,

最終生成了像上圖結構的可執行文件,常見的是windowsexe文件。

可執行文件結構如此,一個程式運行後,進程在記憶體中的結構是如下這樣子。

這幅圖跟可執行文件的結構較為相似,底部是低地址,地址往上遞增。低地址處是代碼區.text已初始化數據區.data未初始化數據區.bss。這幾個區是在程式運行的時候通過記憶體映射附加上去的。在高地址處有個區域是用戶棧,這個棧棧底在高地址處,棧頂在低地址處。棧頂和棧底由兩個指針記錄他們的地址,指針的值存放在CPU寄存器中,分別是%rbp和%rsp。用戶棧的作用有兩個,其一是存放函數調用的棧幀,其二是存放函數調用期間所用到的臨時變數。另外一個區域是位於整個空間中部的運行時堆,這個運行時堆主要是用於給程式申請記憶體空間的時候用的,即調用malloc的時候。動態記憶體分配也屬於虛擬記憶體範疇的內容,但本篇暫不作介紹。

   

下麵則進入虛擬記憶體範疇的內容。從物理記憶體講起,因為物理記憶體大家較為熟悉,一個記憶體上分配了若幹的存儲空間,每個存儲空間都有一個唯一能定位到它的地址稱為物理地址。把一個物理地址傳給記憶體控制器就能往指定地址的記憶體空間上讀/寫數據。

而虛擬記憶體則是現代操作系統對記憶體做了一層抽象。與物理地址對應,虛擬記憶體上的每個存儲空間的地址稱為虛擬地址。儘管是虛擬地址,最終提供或者存放數據的地方還是物理地址,在這個過程中虛擬地址會同通過一個在CPU上的名為記憶體管理單元(簡稱MMU)的硬體翻譯成物理地址,這個過程就叫做地址翻譯。在之前可執行文件的彙編語言截圖中的地址是虛擬地址,進程的記憶體結構中的幾個地址都是虛擬地址。

   

虛擬記憶體實際是存放在磁碟中的,在該空間中劃分了一段一段的連續的空間,這個空間叫作一個"頁",與之前高速緩存中的"塊"概念類似。同樣地,在記憶體中也有一樣的分頁機制。這個頁就用於主存跟磁碟間相互傳遞數據的最小單元。一個虛擬頁被存放到物理記憶體中,這個行為也叫作緩存。磁碟空間比物理記憶體空間要大得多,同樣地虛擬地址空間也會比用作虛擬頁的空間要大。通常一個虛擬頁的狀態有三個

1.未分配:實際上該頁是未存在的,在磁碟上未開闢空間;

2.已分配:與未分配對應,已經在磁碟上開闢了空間;

3.已緩存:該頁已經被分配了,並已經被存放到物理記憶體中。

還有一個比較重要的結構叫做頁表,頁表中每個元素叫作頁表條目(簡稱PTE,PTE的數量與虛擬頁數量相同。頁表是存放在物理記憶體中。每個PTE都有一個有效位,當有效位為0時,表明該頁未分配;當有效位為1,PTE中存放的要麼是虛擬頁的頁號,要麼是已經緩存到物理記憶體的物理地址。

CPU平時只能往物理記憶體讀寫數據,當剛好取到的頁屬於已分配狀態,就會引發缺頁異常,這時候系統會從物理記憶體中選出一頁作為犧牲頁,把PTE指回虛擬記憶體的頁號,把新的頁從磁碟載入到物理記憶體,PTE指向物理記憶體的地址中。

之前也有提及從虛擬地址轉換得出物理地址的過程叫地址翻譯,由CPU裡面的MMU執行。下麵則來講述這個過程。

如上圖所示,一個虛擬地址可以劃分成兩部分,低的p位作為虛擬頁的偏移量,而剩下部分是作為虛擬頁的頁號,實質上就是PTE在頁表上的索引而已。同樣物理地址也是分了兩部分,物理頁偏移量和物理頁號,有個額外的規則是物理頁的偏移量=虛擬頁的偏移量。這裡P=2p,P是頁的大小,位元組為單位。各種量的簡稱如上圖所示。地址翻譯過程的簡述如下:

1.給定一個虛擬地址,劃分出虛擬頁偏移量和虛擬頁號

2.通過頁表基址寄存器找出頁表,找出對應頁號的PTE

3.看從PTE得出頁是否已緩存,不緩存則要找出犧牲頁替換,得出物理頁號

4.把物理頁號和虛擬頁偏移量組合成物理地址

在上述過程中的第三部查找頁表搜出PTE在整個過程中較為耗時,因為涉及到訪存。假設這部分操作利用上緩存則會節省一部分的時間。TLB正是解決了這個問題,TLB叫翻譯後備緩存器(Translation Lookaside Buffer),存放在MMU中。有了這種機制一個虛擬地址的結構將再次被劃分,這次劃分的區域是虛擬頁號

下麵通過一個例子,結合主存,高速緩存,PTE,TLB,頁表來模擬這個地址翻譯的過程

TLB,頁表,高速緩存入下麵所示

   

現在要求出虛擬地址0x03d4的值。

按照前面的條件得出

p=6,所以VPN=14-6=8;

TLB4路組相聯,所以TLB索引占兩位,剩餘的標記位是TLBT=VPN-TLBI=8-2=6

虛擬地址可以拆成

   

TLB行數是3,標記位是03的命中,PPN0DPPN12-6=6位,因為PPO=VPO,所以重新組織後物理地址是0x354,MMU的地址翻譯就到此結束了,。

高速緩存是直接映射,行大小是4位元組,一共有16個組

所以得出以下信息

B=4=2^2,b=2;

S=16=2^4,s=4;

t=m-s-b=12-4-2=6

高速緩存索引號是5,標記位0D命中,偏移是0。最終結果虛擬地址0x03d4的值是0x36。

假設上面TLB不命中,虛擬頁號是0x0F的,查頁表也得出有效位是1PPN0x0D。

   

   

記憶體映射

記憶體映射與虛擬記憶體極為相似,也利用了虛擬記憶體。這兩者也是利用了頁表。記憶體映射是與磁碟上的文件載入有關的。比如我們的可執行文件載入到記憶體,或者一些像libc.so共用庫,也或者是普通一個txt。

   

   

當一個文件要載入到記憶體中時,實際上在虛擬記憶體中開闢了一開虛擬記憶體空間,這個區域的地址是指向了一個頁表,這個頁表類似於虛擬記憶體那樣與磁碟的內容進行關聯。比如現在要讀取某共用庫的一個地址的內容,該地址是位於進程的虛擬記憶體的共用庫的區域內,而這個地址指向的是一個記憶體映射的頁表PTE。如同虛擬定址那樣,如果該PTE是無效的或者是指向文件中的某個地址,則會發生缺頁異常,然後會就在物理記憶體中選中一個犧牲的物理頁替換成這個待讀取的頁。載入到物理頁完畢後,就可以在物理頁中讀取想要的數據。

記憶體映射有利於節省記憶體空間,現在如libc.so這樣的文件載入到記憶體中,如果每個進程都載入一份到記憶體中那回造成浪費,現在利用記憶體映射,每個進程都可以把他們共同需要的libc.so映射到同一片的記憶體區域。

。另外一種場景,假設兩個進程A和B都打開了某個文件,現在有一個進程B需要寫文件的內容,但是另外一個A進程完全不能受到這次寫的影響,那進程B則會在物理記憶體中拷貝一份跟原有頁一樣的內容,把虛擬記憶體指向到這個新的頁。

用戶態的記憶體映射實際上利用了一個叫mmap的函數。函數的定義如下

void* mmap(void* start ,size_t length , int prot , int flags , int fd , off_t offset);

Start是待映射的虛擬記憶體的起始地址

length是映射的長度

fd是文件描述符,指定了磁碟文件中的起始地址

offset是最後一個參數,他指定了開始映射的地址距離文件起始地址的偏移量。

prot是映射後虛擬記憶體的訪問許可權,這個許可權是可讀可寫之類的

flag指定了映射的對象類型,這些類型是匿名對象,共用對象,私有對象之類的。

本篇屬於個人學習完的總結。文中有摘抄了網上或書籍中的圖片。如有錯誤的請及時指出,以便本人及時更正。謝謝


您的分享是我們最大的動力!

-Advertisement-
Play Games
更多相關文章
  • 轉自:[LCD顯示異常分析——撕裂(tear effect) ](https://blog.csdn.net/hexiaolong2009/article/details/79319512) 概述 在上一篇《 "LCD顯示異常分析——開機閃現花屏" 》中,我們一起分析了開機花屏的問題,在這一篇中,我 ...
  • ——一個環境呆久了,比較容易進入安逸,再由安逸轉為焦慮。這也許就是缺乏長遠規劃導致的,也有可能是內功不夠。 目前的工作基本上是工作在user space層,偏向業務邏輯。本身底子不是非常厚,加之最近段時間沒有好好的學習積澱,底子就顯得更薄弱了。 之前微軟那邊就有聯繫我,但是之前一段時間公司實在是太忙 ...
  • Win10隱藏了20%的網速,下麵叫你怎麼釋放它: 1.按Win+R調出運行,輸入gpedit.msc點擊確定; 2.點擊windows設置,右擊基於策略Qos,選擇高級Qos設置: 3.勾選如圖方框,選擇級別3: 4.選擇管理模板-網路-Qos數據包計劃程式,雙擊限制可保留帶寬,進入: 5.選擇已 ...
  • RHEL6.5 DHCP伺服器搭建: DHCP伺服器是用來分配給其它客戶端IP地址用的,在RHEL 6.5中DHCP伺服器搭建方法如下: 第一步,通過yum安裝dhcp服務: 命令:yum install dhcp 第二步:備份dhcp的主配置文件: 命令:mv /etc/dhcp/dhcpd.co ...
  • 轉自[LCD顯示異常分析——開機閃現花屏 ](https://blog.csdn.net/hexiaolong2009/article/details/79190789) 最近在工作中,有同事遇到LCD開機瞬間會閃現雪花屏的問題,而這類問題都有個共同點,那就是都發生在帶GRAM的屏上,同樣的問題,在 ...
  • 一、Centos7使用firewall的管理防火牆 1.firewalld基本使用 啟動:systemctl start firewalld 關閉:systemctl stop firewalld 狀態:systemctl status firewalld 開機禁用:systemctl disabl ...
  • 參考鏈接: Windows下如何查看某個埠被誰占用 1. 遇到的問題 在Windows下的IDEA中啟動Web服務顯示8080埠被占用,程式無法正確啟動。 2. 解決思路 關閉占用進程的應用 通過Google檢索遇到的問題 查到了 Windows下如何查看某個埠被誰占用 3. 解決方案 3.1 ...
  • 一.初識bash shell 1.1 啟動 shell GNU bash shell 能提供對Linux系統的互動式訪問。通常是在用戶登錄終端時啟動,登錄時系統啟動shell依賴於用戶賬戶的配置。etc/passwd文件包含了所有系統用戶列表以及每個用戶的基本配置信息。 如上圖:最後一個欄位,告訴用 ...
一周排行
    -Advertisement-
    Play Games
  • 移動開發(一):使用.NET MAUI開發第一個安卓APP 對於工作多年的C#程式員來說,近來想嘗試開發一款安卓APP,考慮了很久最終選擇使用.NET MAUI這個微軟官方的框架來嘗試體驗開發安卓APP,畢竟是使用Visual Studio開發工具,使用起來也比較的順手,結合微軟官方的教程進行了安卓 ...
  • 前言 QuestPDF 是一個開源 .NET 庫,用於生成 PDF 文檔。使用了C# Fluent API方式可簡化開發、減少錯誤並提高工作效率。利用它可以輕鬆生成 PDF 報告、發票、導出文件等。 項目介紹 QuestPDF 是一個革命性的開源 .NET 庫,它徹底改變了我們生成 PDF 文檔的方 ...
  • 項目地址 項目後端地址: https://github.com/ZyPLJ/ZYTteeHole 項目前端頁面地址: ZyPLJ/TreeHoleVue (github.com) https://github.com/ZyPLJ/TreeHoleVue 目前項目測試訪問地址: http://tree ...
  • 話不多說,直接開乾 一.下載 1.官方鏈接下載: https://www.microsoft.com/zh-cn/sql-server/sql-server-downloads 2.在下載目錄中找到下麵這個小的安裝包 SQL2022-SSEI-Dev.exe,運行開始下載SQL server; 二. ...
  • 前言 隨著物聯網(IoT)技術的迅猛發展,MQTT(消息隊列遙測傳輸)協議憑藉其輕量級和高效性,已成為眾多物聯網應用的首選通信標準。 MQTTnet 作為一個高性能的 .NET 開源庫,為 .NET 平臺上的 MQTT 客戶端與伺服器開發提供了強大的支持。 本文將全面介紹 MQTTnet 的核心功能 ...
  • Serilog支持多種接收器用於日誌存儲,增強器用於添加屬性,LogContext管理動態屬性,支持多種輸出格式包括純文本、JSON及ExpressionTemplate。還提供了自定義格式化選項,適用於不同需求。 ...
  • 目錄簡介獲取 HTML 文檔解析 HTML 文檔測試參考文章 簡介 動態內容網站使用 JavaScript 腳本動態檢索和渲染數據,爬取信息時需要模擬瀏覽器行為,否則獲取到的源碼基本是空的。 本文使用的爬取步驟如下: 使用 Selenium 獲取渲染後的 HTML 文檔 使用 HtmlAgility ...
  • 1.前言 什麼是熱更新 游戲或者軟體更新時,無需重新下載客戶端進行安裝,而是在應用程式啟動的情況下,在內部進行資源或者代碼更新 Unity目前常用熱更新解決方案 HybridCLR,Xlua,ILRuntime等 Unity目前常用資源管理解決方案 AssetBundles,Addressable, ...
  • 本文章主要是在C# ASP.NET Core Web API框架實現向手機發送驗證碼簡訊功能。這裡我選擇是一個互億無線簡訊驗證碼平臺,其實像阿裡雲,騰訊雲上面也可以。 首先我們先去 互億無線 https://www.ihuyi.com/api/sms.html 去註冊一個賬號 註冊完成賬號後,它會送 ...
  • 通過以下方式可以高效,並保證數據同步的可靠性 1.API設計 使用RESTful設計,確保API端點明確,並使用適當的HTTP方法(如POST用於創建,PUT用於更新)。 設計清晰的請求和響應模型,以確保客戶端能夠理解預期格式。 2.數據驗證 在伺服器端進行嚴格的數據驗證,確保接收到的數據符合預期格 ...