系統記憶體管理:虛擬記憶體、記憶體分段與分頁、頁表緩存TLB以及Linux記憶體管理

来源:https://www.cnblogs.com/guoxiaoyu/archive/2023/08/25/17653050.html
-Advertisement-
Play Games

虛擬記憶體的主要作用是提供更大的地址空間,使得每個進程都可以擁有大量的虛擬記憶體,而不受物理記憶體大小的限制。此外,虛擬記憶體還可以提供記憶體保護和共用的機制,保護每個進程的記憶體空間不被其他進程非法訪問,並允許多個進程共用同一份物理記憶體數據,提高了系統的資源利用率。虛擬記憶體的實現方式有分段和分頁兩種,其中分頁... ...


虛擬記憶體

虛擬記憶體是一種操作系統提供的機制,用於將每個進程分配的獨立的虛擬地址空間映射到實際的物理記憶體地址空間上。通過使用虛擬記憶體,操作系統可以有效地解決多個應用程式直接操作物理記憶體可能引發的衝突問題。

在使用虛擬記憶體的情況下,每個進程都有自己的獨立的虛擬地址空間,它們不能直接訪問物理記憶體地址。當程式訪問虛擬記憶體地址時,操作系統會進行地址轉換,將虛擬地址映射到物理地址上,這樣不同的進程運行時,寫入的是不同的物理地址,避免了互相覆蓋指針的問題。

虛擬記憶體的使用使得每個進程都可以擁有相同的虛擬地址空間,而不用擔心與其他進程的地址衝突。操作系統負責管理虛擬地址和物理地址之間的映射關係,併在需要時進行地址轉換。這樣,進程可以以一種透明的方式訪問記憶體,無需關心記憶體的實際物理位置。

image

通過虛擬記憶體機制,操作系統能夠更好地管理系統記憶體資源,提供更高的安全性和穩定性。它可以為每個進程提供獨立的地址空間,保護進程間的數據隔離,同時也可以有效地利用物理記憶體,將不常用的數據交換到磁碟上(交換區),以提供更大的可用記憶體空間。

記憶體分段

在分段機制下,虛擬地址由兩部分組成:段選擇子和段內偏移量。段選擇子是一個索引,用於指定要訪問的段的起始地址和長度。段內偏移量則表示在該段內的具體位置。

操作系統會維護一個段表,其中包含了每個段的起始地址和長度信息。當程式訪問一個虛擬地址時,操作系統會通過段選擇子從段表中找到對應的段描述符,然後根據段描述符中的信息計算出物理地址。

具體的映射過程如下:

  1. 程式訪問虛擬地址,通過段選擇子找到對應的段描述符。
  2. 根據段描述符中的基址和長度信息,計算出段的起始物理地址。
  3. 將段的起始物理地址與段內偏移量相加,得到最終的物理地址。

image

不過,需要註意的是,分段機制可能會導致記憶體碎片的問題,因為不同段的大小可能不同,導致一些碎片化的空間無法被利用。當不夠記憶體分配的時候,會選擇使用記憶體交換,先把一塊正在使用的記憶體移到磁碟中,然後再移回來把中間留的記憶體縫隙全用上,雖然解決了記憶體碎片的問題,但是這個交換操作很慢,效率低,看下圖示:

image

虛擬記憶體、分段和記憶體交換似乎解決了同時運行多個程式的問題,但仍存在性能瓶頸。由於硬碟訪問速度較慢,每次記憶體交換都需要將大段連續的記憶體數據寫入硬碟。因此,如果交換的是占用大量記憶體空間的程式,整個系統會變得卡頓。

為瞭解決記憶體分段的碎片和提高記憶體交換效率,引入了記憶體分頁機制。

記憶體分頁

記憶體分頁是將整個虛擬和物理記憶體空間劃分為固定大小的連續記憶體塊,稱為頁(Page)。在Linux下,每一頁的大小通常為4KB。虛擬地址與物理地址之間通過頁表進行映射,頁表存儲在CPU的記憶體管理單元(MMU)中,從而CPU可以直接通過MMU找到實際訪問的物理記憶體地址。

虛擬地址與物理地址之間通過頁表來映射,如下圖:

image

由於記憶體空間事先劃分為固定大小的頁,不會像分段機制那樣產生碎片。當釋放記憶體時,以頁為單位進行釋放,避免了無法利用的小記憶體塊。

如果記憶體空間不足,操作系統會將其他正在運行的進程中的"最近未使用"的記憶體頁面暫時存儲到硬碟上,稱為換出(Swap Out)。當需要時,再將頁面載入回記憶體,稱為換入(Swap In)。因此,每次寫入硬碟的是少量的一頁或幾頁,不會花費太多時間,從而提高了記憶體交換的效率。

image

簡單分頁

簡單分頁存在空間上的缺陷。在操作系統可以同時運行大量進程的情況下,頁表會變得非常龐大。在32位環境下,虛擬地址空間為4GB,假設頁的大小為4KB,就需要大約100萬個頁。每個頁表項需要4位元組來存儲,所以整個4GB空間的映射需要4MB的記憶體來存儲頁表。

儘管4MB的頁表看起來並不算太大,但要註意每個進程都有自己的虛擬地址空間,也就是說每個進程都有自己的頁表。如果有100個進程,就需要400MB的記憶體來存儲頁表,這對於記憶體來說是相當大的開銷,更不用說64位環境下了。

多級頁表

要解決上述問題,我們可以採用一種叫做多級頁表(Multi-Level Page Table)的解決方案。在之前我們已經瞭解到,在32位環境下,頁大小為4KB的情況下,一個進程的頁表需要存儲100多萬個頁表項,每個項占用4位元組的空間,因此一個頁表需要4MB的記憶體空間。

為了節省記憶體空間,我們可以將單級頁表進行分頁,將一個頁表(一級頁表)分為1024個頁表(二級頁表),每個二級頁表包含1024個頁表項,形成二級分頁結構。這樣一級頁表覆蓋整個4GB的虛擬地址空間,而對於未使用的頁表項,不會創建對應的二級頁表,只在需要時才創建。如下圖所示:

image

換個角度來看,大多數程式未使用到整個4GB的虛擬地址空間,因此部分頁表項是空的,沒有分配實際的記憶體空間。在物理記憶體緊張的情況下,操作系統會將最近一段時間未訪問的頁表換出到硬碟,從而釋放物理記憶體。使用二級分頁,一級頁表只需要覆蓋整個4GB的虛擬地址空間,而未使用的頁表項不需要創建對應的二級頁表。假設只有20%的一級頁表項被使用,那麼頁表占用的記憶體空間只有0.804MB,相比於單級頁表的4MB,記憶體節約非常巨大。

為什麼不分級的頁表無法實現這樣的記憶體節約呢?從頁表的性質來看,頁表保存在記憶體中,其主要作用是將虛擬地址翻譯為物理地址。如果在頁表中找不到對應的頁表項,電腦系統將無法正常工作。因此,頁表必須覆蓋整個虛擬地址空間。而不分級的頁表需要100多萬個頁表項進行映射,而二級分頁只需要1024個頁表項(一級頁表覆蓋整個虛擬地址空間,二級頁表在需要時創建)。

頁表緩存TLB(Translation Lookaside Buffer)

TLB(Translation Lookaside Buffer)是一個位於CPU晶元中的緩存,用於存儲程式中最常訪問的頁表項,以加快虛擬地址到物理地址的轉換速度。多級頁表雖然解決了空間上的問題,但是增加了轉換的工序,導致時間上的開銷。然而,由於程式的局部性原理,程式執行期間通常僅限於某一部分,訪問的存儲空間也局限於某個記憶體區域。因此,通過將最常訪問的頁表項存儲到TLB這個硬體緩存中,可以更快地進行地址轉換。

在CPU晶元中,記憶體管理單元(Memory Management Unit)晶元負責處理地址轉換和TLB的訪問與交互。當CPU進行定址時,首先會查找TLB,如果找到了對應的頁表項,就可以直接進行物理地址的訪問,避免了繼續查找常規頁表的開銷。

由於TLB中存儲的是程式最常訪問的幾個頁表項,所以TLB的命中率通常是很高的。這是因為程式執行過程中,訪問的頁表項相對固定。通過利用TLB,可以大大提高地址轉換的速度,加快程式的執行效率。

Linux記憶體管理

image

Linux記憶體管理涉及邏輯地址和線性地址的轉換。邏輯地址是程式使用的地址,而線性地址是通過段式記憶體管理映射的地址,也稱為虛擬地址。

Linux的虛擬地址空間分為內核空間和用戶空間兩部分。32位系統中,內核空間占用1G,剩下的3G是用戶空間;64位系統中,內核空間和用戶空間都是128T,分別占據記憶體空間的最高和最低處。如下所示:

image

進程在用戶態時只能訪問用戶空間記憶體,進入內核態後才能訪問內核空間記憶體。雖然每個進程都有獨立的虛擬記憶體,但虛擬記憶體中的內核地址關聯的是相同的物理記憶體,這樣進程切換到內核態後就可以方便地訪問內核空間記憶體。

總結

虛擬記憶體是操作系統提供的一種機制,通過將每個進程分配的獨立的虛擬地址空間映射到實際的物理記憶體地址空間上,解決了多個應用程式直接操作物理記憶體可能引發的衝突問題。虛擬記憶體的使用使得每個進程都可以擁有相同的虛擬地址空間,而不用擔心與其他進程的地址衝突。通過虛擬記憶體機制,操作系統能夠更好地管理系統記憶體資源,提供更高的安全性和穩定性。虛擬記憶體的實現方式有分段和分頁,其中分頁機制更為常用,採用多級頁表的方式節約了記憶體空間。頁表緩存TLB能夠加快虛擬地址到物理地址的轉換速度。Linux的記憶體管理涉及邏輯地址和線性地址的轉換,將虛擬地址空間分為內核空間和用戶空間,方便進程訪問內核空間記憶體。


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

-Advertisement-
Play Games
更多相關文章
  • ## 13.1、環境搭建 ### 13.1.1、創建module ![image](https://img2023.cnblogs.com/blog/2052479/202308/2052479-20230821075157720-1152690363.png) ### 13.1.2、選擇maven ...
  • 知乎網友問 鏈式重載是我自己創造的一個詞,意思是方法A里處理一下參數,return另一個方法A,第二個方法A里處理一下參數調第三個方法A,就這樣無限迴圈下去直到調到真正能出結果的方法A。 本人學藝不精,偶然進行C#開發,感覺看代碼要吐。比如看到某處調用方法A,除非有某個特征顯眼的參數,否則根本不知道 ...
  • # [The database operation was expected to affect 1 row(s), but actually affected 0 row(s); 解決樂觀併發](https://www.raokun.top/archives/thedatabaseoperatio ...
  • Trigger:當某些條件滿足時會觸發一個行為。 一、觸發器的類型 數據變化觸髮型:Trigger / DataTrigger 多條件觸髮型:MultiTrigger / MultiDataTrigger 事件觸髮型:EventTrigger 二、Trigger Trigger:Property用來 ...
  • # Unity UGUI的Toggle(覆選框)組件的介紹及使用 ## 1. 什麼是Toggle組件? Toggle(覆選框)是Unity UGUI中的一個常用組件,用於實現覆選框的功能。它可以被選中或取消選中,並且可以代碼通過其制控狀態。 ## 2. Toggle組件的工作原理 組Toggle件由 ...
  • 圖形系部分主要有`Shape`和`Goemetry`兩大類,可以直接對`Shape`進行排版、設定風格和數據綁定,後者則需要通過視覺元素才能在屏幕上顯示出來。動畫則一般分為簡單動畫、關鍵幀動畫以及沿路徑運動的動畫,日常使用過程種應該是關鍵幀動畫用的多一點,當然除了文章中例舉的關鍵幀類型,還有其他很多... ...
  • 哈嘍大家好,我是鹹魚 在《[SELinux 入門 pt.1](https://mp.weixin.qq.com/s?__biz=MzkzNzI1MzE2Mw==&mid=2247486365&idx=1&sn=4b81b3cc70b085eec6f0a595fda719fb&chksm=c2930b ...
  • 平時使用windows電腦和手機的時候,配置時間、時區都非常的簡便。但在命令行的linux下,就不知如何下手。本文就Centos7舉例,依次說明下時間日期和NTP\CHRONY的配置。 由於在伺服器側時間同步常用於集群之間,所以本文後面會針對集群間的配置做舉例。文中涉及到的網路安裝軟體部分,預設為在 ...
一周排行
    -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.數據驗證 在伺服器端進行嚴格的數據驗證,確保接收到的數據符合預期格 ...