從硬件角度看內(nèi)存管理:解鎖計算機底層性能原理
在計算機的復雜世界里,內(nèi)存管理就像一位幕后指揮官,掌控著硬件性能的關鍵。從硬件角度深入理解內(nèi)存管理,能解鎖計算機底層性能的奧秘。計算機硬件猶如精密協(xié)作的交響樂團,CPU 作為核心,以驚人速度處理數(shù)據(jù),而內(nèi)存則是其緊密協(xié)作的伙伴。內(nèi)存,這個計算機的 “臨時倉庫”,承擔著存儲正在運行程序和數(shù)據(jù)的重任,為 CPU 提供高速數(shù)據(jù)訪問通道。內(nèi)存與硬盤有別,它具有易失性,斷電后數(shù)據(jù)瞬間消失,但其讀寫速度卻遠非硬盤可比。像常見的動態(tài)隨機存取內(nèi)存(DRAM),雖需定期刷新數(shù)據(jù),卻因高存儲密度和低成本成為主流;靜態(tài)隨機存取內(nèi)存(SRAM)速度更快,不過成本高、存儲密度低。
如今的雙倍數(shù)據(jù)速率同步動態(tài)隨機存取內(nèi)存(DDR SDRAM),如 DDR4、DDR5,更是憑借高數(shù)據(jù)傳輸速率,大幅提升了計算機性能。在內(nèi)存與 CPU 之間,還有緩存這一 “秘密武器”。緩存是位于兩者之間的高速存儲器,容量小卻速度極快,常以 L1、L2、L3 等多級形式存在。它利用程序訪問數(shù)據(jù)的局部性原理,將頻繁訪問的數(shù)據(jù)提前存儲,當 CPU 請求數(shù)據(jù)時,先在緩存中查找,若命中,數(shù)據(jù)便能迅速被獲取,大大提高了程序執(zhí)行效率。接下來,就讓我們一同深入探索從硬件角度出發(fā)的內(nèi)存管理,挖掘更多計算機底層性能的原理。
一、內(nèi)存管理的硬件基石
1.1內(nèi)存管理單元(MMU):地址轉(zhuǎn)換的幕后英雄
MMU是Memory Management Unit的縮寫,中文名是內(nèi)存管理單元,有時稱作分頁內(nèi)存管理單元(英語:paged memory management unit,縮寫為PMMU)。它是一種負責處理中央處理器(CPU)的內(nèi)存訪問請求的計算機硬件。它的功能包括虛擬地址到物理地址的轉(zhuǎn)換(即虛擬內(nèi)存管理)、內(nèi)存保護、中央處理器高速緩存的控制,在較為簡單的計算機體系結(jié)構(gòu)中,負責總線的仲裁以及存儲體切換(bank switching,尤其是在8位的系統(tǒng)上)。
內(nèi)存管理單元(MMU)的一個重要功能是使系統(tǒng)能夠運行多個任務,作為獨立程序在自己的私有虛擬內(nèi)存空間中運行。它們不需要了解系統(tǒng)的物理內(nèi)存映射,即硬件實際使用的地址,也不需要了解可能同時執(zhí)行的其他程序。
圖片
打個比方,我們可以把計算機的內(nèi)存想象成一個大型的倉庫,里面存放著各種各樣的物資(數(shù)據(jù)和程序)。而運行在計算機上的眾多程序,就如同一個個前來領取物資的客戶。如果沒有一個有效的管理機制,這些客戶可能會在倉庫里隨意翻找,不僅效率低下,還可能會出現(xiàn)混亂,導致物資的損壞或丟失。
而 MMU 就像是這個倉庫的大管家,它制定了一套嚴格而有序的管理規(guī)則。每個客戶(程序)在訪問倉庫(內(nèi)存)時,都需要通過 MMU 這個大管家進行 “登記” 和 “授權(quán)”,然后由大管家將客戶的 “需求指令”(虛擬地址)準確無誤地轉(zhuǎn)換為倉庫中實際的 “物資存放位置”(物理地址),這樣客戶就能順利地獲取到自己需要的物資,同時也保證了倉庫的秩序和物資的安全。
從專業(yè)的角度來說,MMU 是一種負責處理中央處理器(CPU)的內(nèi)存訪問請求的計算機硬件。它的出現(xiàn),讓計算機系統(tǒng)能夠更加高效、穩(wěn)定地運行多個任務,仿佛為每個任務都打造了一個屬于它們自己的獨立小世界,互不干擾,各自精彩。
(1)MMU的核心功能
①虛擬地址與物理地址的轉(zhuǎn)換魔法
在計算機的內(nèi)存世界里,存在著兩種重要的地址概念:虛擬地址和物理地址。虛擬地址是程序在運行時所使用的地址,就像是我們在地圖上規(guī)劃的一條虛擬路線,它并不直接對應實際的物理內(nèi)存位置。而物理地址則是內(nèi)存芯片上實實在在的地址,是數(shù)據(jù)真正存儲的地方,就如同地圖上的實際地點。
那么,MMU 是如何將虛擬地址轉(zhuǎn)換為物理地址的呢?這就要借助頁表這個神奇的工具了。頁表就像是一本詳細的地址翻譯字典,記錄著虛擬地址和物理地址之間的映射關系。當 CPU 發(fā)出一個虛擬地址請求時,MMU 就會像查字典一樣,在頁表中查找對應的物理地址。
具體來說,虛擬地址會被劃分成頁號和頁內(nèi)偏移兩部分。頁號就像是字典的索引,通過它可以快速定位到頁表中對應的條目,而這個條目里就存儲著對應的物理頁號。然后,將物理頁號和頁內(nèi)偏移組合起來,就得到了最終的物理地址,從而能夠準確地訪問到內(nèi)存中的數(shù)據(jù)。
舉個例子,假設我們有一個程序要訪問虛擬地址 0x12345678。MMU 首先會提取出頁號,比如是 0x1234,然后在頁表中查找這個頁號對應的條目。假設找到的條目顯示對應的物理頁號是 0x5678,而頁內(nèi)偏移是 0x9ABC,那么最終的物理地址就是 0x56789ABC。通過這樣的轉(zhuǎn)換,程序就能夠順利地訪問到它所需要的數(shù)據(jù),就好像我們通過地圖上的路線規(guī)劃找到了實際的目的地一樣。
mmu開啟以后會有以下特點:
- 多個程序獨立運行
- 虛擬地址是連續(xù)的(物理內(nèi)存可以有碎片)
- 允許操作系統(tǒng)管理內(nèi)存
下圖顯示的系統(tǒng)說明了內(nèi)存的虛擬和物理視圖。單個系統(tǒng)中的不同處理器和設備可能具有不同的虛擬地址映射和物理地址映射。操作系統(tǒng)編寫程序,使MMU在這兩個內(nèi)存視圖之間進行轉(zhuǎn)換:
圖片
要做到這一點,虛擬內(nèi)存系統(tǒng)中的硬件必須提供地址轉(zhuǎn)換,即將處理器發(fā)出的虛擬地址轉(zhuǎn)換為主內(nèi)存中的物理地址。MMU使用虛擬地址中最重要的位來索引轉(zhuǎn)換表中的條目,并確定正在訪問哪個塊。MMU將代碼和數(shù)據(jù)的虛擬地址轉(zhuǎn)換為實際系統(tǒng)中的物理地址。該轉(zhuǎn)換將在硬件中自動執(zhí)行,并且對應用程序是透明的。除了地址轉(zhuǎn)換之外,MMU還可以控制每個內(nèi)存區(qū)域的內(nèi)存訪問權(quán)限、內(nèi)存順序和緩存策略。
MMU對執(zhí)行的任務或應用程序可以不了解系統(tǒng)的物理內(nèi)存映射,也可以不了解同時運行的其他程序。每個程序可以使用相同的虛擬內(nèi)存地址空間。即使物理內(nèi)存是碎片化的,還可以使用一個連續(xù)的虛擬內(nèi)存映射。此虛擬地址空間與系統(tǒng)中內(nèi)存的實際物理映射分開的。應用程序被編寫、編譯和鏈接,以在虛擬內(nèi)存空間中運行。
圖片
如上圖所示,TLB是MMU中最近訪問的頁面翻譯的緩存。對于處理器執(zhí)行的每個內(nèi)存訪問,MMU將檢查轉(zhuǎn)換是否緩存在TLB中。如果所請求的地址轉(zhuǎn)換在TLB中導致命中,則該地址的翻譯立即可用。TLB本質(zhì)是一塊高速緩存。數(shù)據(jù)cache緩存地址(虛擬地址或者物理地址)和數(shù)據(jù)。TLB緩存虛擬地址和其映射的物理地址。TLB根據(jù)虛擬地址查找cache,它沒得選,只能根據(jù)虛擬地址查找。所以TLB是一個虛擬高速緩存。
每個TLB entry通常不僅包含物理地址和虛擬地址,還包含諸如內(nèi)存類型、緩存策略、訪問權(quán)限、地址空間ID(ASID)和虛擬機ID(VMID)等屬性。如果TLB不包含處理器發(fā)出的虛擬地址的有效轉(zhuǎn)換,稱為TLB Miss,則將執(zhí)行外部轉(zhuǎn)換頁表查找。MMU內(nèi)的專用硬件使它能夠讀取內(nèi)存中的轉(zhuǎn)換表。
然后,如果翻譯頁表沒有導致頁面故障,則可以將新加載的翻譯緩存在TLB中,以便進行后續(xù)的重用。簡單概括一下就是:硬件存在TLB后,虛擬地址到物理地址的轉(zhuǎn)換過程發(fā)生了變化。虛擬地址首先發(fā)往TLB確認是否命中cache,如果cache hit直接可以得到物理地址。否則,一級一級查找頁表獲取物理地址。并將虛擬地址和物理地址的映射關系緩存到TLB中。
如果操作系統(tǒng)修改了可能已經(jīng)緩存在TLB中的轉(zhuǎn)換的entry,那么操作系統(tǒng)就有責任使這些未更新的TLB entry invaild。當執(zhí)行A64代碼時,有一個TLBI,它是一個TLB無效的指令:
TLBI <type><level>{IS} {, <Xt>}TLB可以保存固定數(shù)量的entry。可以通過由轉(zhuǎn)換頁表遍歷引起的外部內(nèi)存訪問次數(shù)和獲得高TLB命中率來獲得最佳性能。ARMv8-A體系結(jié)構(gòu)提供了一個被稱為連續(xù)塊entry的特性,以有效地利用TLB空間。轉(zhuǎn)換表每個entry都包含一個連續(xù)的位。當設置時,這個位向TLB發(fā)出信號,表明它可以緩存一個覆蓋多個塊轉(zhuǎn)換的單個entry。查找可以索引到連續(xù)塊所覆蓋的地址范圍中的任何位置。因此,TLB可以為已定義的地址范圍緩存一個entry從而可以在TLB中存儲更大范圍的虛擬地址。
②內(nèi)存保護的堅固防線
MMU 不僅是地址轉(zhuǎn)換的高手,還是內(nèi)存保護的堅固防線。在多任務的操作系統(tǒng)環(huán)境下,多個進程同時運行,就像一個熱鬧的大社區(qū)里住著許多戶人家。如果沒有有效的管理,這些進程可能會互相干擾,就像鄰居之間隨意闖入對方的房子一樣。
MMU 通過硬件機制實現(xiàn)了內(nèi)存訪問授權(quán),為每個進程分配了獨立的地址空間,就像給每個家庭都分配了獨立的房子,互不干擾。當一個進程試圖訪問內(nèi)存時,MMU 會檢查該進程是否有權(quán)限訪問目標內(nèi)存區(qū)域。只有當進程具有相應的訪問權(quán)限時,MMU 才會允許這次訪問,否則就會阻止訪問,并向操作系統(tǒng)報告,就像保安會阻止沒有權(quán)限的人進入特定區(qū)域一樣。
例如,一個進程 A 正在運行,它只能訪問屬于自己地址空間內(nèi)的內(nèi)存。如果進程 A 試圖訪問進程 B 的內(nèi)存區(qū)域,MMU 會立即發(fā)現(xiàn)這個非法訪問行為,并阻止它,從而保證了系統(tǒng)的穩(wěn)定性和安全性。這種內(nèi)存保護機制有效地防止了進程之間的非法訪問,避免了因一個進程的錯誤而導致整個系統(tǒng)崩潰的情況,就像堅固的圍墻保護著每個家庭的安全,讓整個社區(qū)能夠和諧穩(wěn)定地運轉(zhuǎn)。
1.2頁表:地址映射的導航圖
頁表是內(nèi)存管理中不可或缺的部分,它就像是一本詳細的導航圖,記錄著虛擬地址與物理地址之間的映射關系 。在 32 位系統(tǒng)中,若頁面大小為 4KB,虛擬地址空間為 4GB,那么頁表可能會有 1048576(2 的 20 次方)個表項,每個表項對應一個 4KB 的頁面 。為了節(jié)省內(nèi)存空間,現(xiàn)代操作系統(tǒng)普遍采用多級頁表結(jié)構(gòu) 。以二級頁表為例,虛擬地址被進一步劃分為外層頁號、內(nèi)層頁號和頁內(nèi)偏移 。外層頁號用于索引一級頁表(頁目錄),找到對應的二級頁表起始地址;內(nèi)層頁號再用于索引二級頁表,找到對應的物理頁框號;最后,物理頁框號與頁內(nèi)偏移組合得到物理地址 。這樣,對于那些未使用的虛擬地址空間,就不需要為其分配實際的頁表項,大大節(jié)省了內(nèi)存開銷 。
①在文件的讀寫中。在普通進程的匿名映射區(qū)操作中。在文件的讀寫中,進程對一個文件發(fā)起讀請求,如果沒喲對應的物理內(nèi)存頁,則內(nèi)核處理程序首先在頁緩存中查找,如果找到直接返回。如果沒找到,那么再分配空間,把內(nèi)容從文件讀入內(nèi)存,插入頁緩存,并返回,這里讀操作雖然是一個頁面發(fā)生的未命中,但是很大程度上會讀取多個連續(xù)頁面到內(nèi)存中,只不過返回調(diào)用指定頁面,因為實際情況中,很少僅僅需要讀取一個頁面,這樣后續(xù)如果在需要訪問還是需要進行磁盤IO,磁盤尋道時間往往比讀取時間還要長,為了提高IO效率,就有了上述的預讀機制。。
②在普通進程的匿名映射中,比如進程申請的比較大的堆空間(大于128kb的都是利用MMAP映射的),這些空間的內(nèi)容如果在一段時間內(nèi)沒被釋放 且在一段時間內(nèi)沒被訪問,則有可能被系統(tǒng)內(nèi)存管理器交換到外存以騰出更多的物理內(nèi)存空間。下次在進程訪問該內(nèi)容,根據(jù)頁表查找發(fā)現(xiàn)物理頁面不在內(nèi)存,則需要調(diào)用缺頁異常處理程序。異常處理程序判斷該頁時被換出到外存,那么首先也是在頁緩存中找,如果找到就返回;否則,從交換分區(qū)或者交換文件中把對應的文件讀入內(nèi)存。這里所說的頁緩存和1中描述的頁緩存是一類緩存,但是并不是一個,1中的頁緩存是文件系統(tǒng)相關的,在磁盤上對應著具體的文件;在頁面回收的時候需要回寫到磁盤即同步一下;而2中的頁緩存其實是一種交換緩存,在頁面回收的時候只能是換出到交換分區(qū)或者交換文件,不存在同步的操作。
(1)Linux內(nèi)核頁表結(jié)構(gòu)
在Linux內(nèi)核中,頁表是用來管理虛擬內(nèi)存和物理內(nèi)存之間映射關系的數(shù)據(jù)結(jié)構(gòu)。Linux采用了兩級頁表(two-level page table)的結(jié)構(gòu),具體包括以下幾個部分:
- 一級頁表(Level 1 Page Table):也稱為頂層頁表(Top-Level Page Table),它是整個頁表層次結(jié)構(gòu)的入口點。一級頁表的條目數(shù)與物理內(nèi)存大小相關,每個條目指向二級頁表。
- 二級頁表(Level 2 Page Table):也稱為中間層頁表(Intermediate Page Table)。二級頁表將虛擬地址空間劃分成更小的區(qū)域,并對應到三級頁表。
- 三級頁表(Level 3 Page Table):也稱為底層頁表(Leaf Page Table)。三級頁表對應著最細粒度的頁面大小,通常是4KB或2MB。每個條目包含了虛擬地址和物理地址之間的映射關系。
通過多級頁表結(jié)構(gòu),Linux 內(nèi)核能夠有效地管理大型虛擬地址空間和物理內(nèi)存。當進程訪問一個虛擬地址時,內(nèi)核會根據(jù)虛擬地址在不同層次的頁表中進行查找和轉(zhuǎn)換,最終得到對應的物理地址。
需要注意的是,在64位版本的 Linux 內(nèi)核中,由于更廣闊的虛擬地址空間和更大容量的物理內(nèi)存支持,可能會有更多級的頁表結(jié)構(gòu)。具體的層次結(jié)構(gòu)和細節(jié)可能因不同的架構(gòu)、配置和內(nèi)核版本而有所變化,上述描述僅為一般情況下的常見頁表結(jié)構(gòu)。
①頁表項
頁表項(Page Table Entry)是頁表中的每個條目,用于描述虛擬地址與物理地址之間的映射關系。每個頁表項通常包含以下字段:
- 物理頁面基址(Physical Page Base Address):指向?qū)奈锢韮?nèi)存頁面的起始地址。
- 標志位(Flags):用于控制頁面的訪問權(quán)限、緩存策略和其他特性。常見的標志位包括可讀/寫/執(zhí)行權(quán)限、緩存禁用、全局標志等。
- 狀態(tài)位(Status Bits):記錄頁面的狀態(tài)信息,如臟頁標記、引用位等。
- 其他輔助字段:可能包含一些額外信息,如頁表層次索引、保留位等。
根據(jù)操作系統(tǒng)和硬件架構(gòu)的不同,頁表項可能有不同的結(jié)構(gòu)和長度。例如,在x86體系結(jié)構(gòu)上,一個典型的32位頁表項長度為4字節(jié)(32 bits),而在64位上則是8字節(jié)(64 bits)。這些長度限制了能夠表示的物理內(nèi)存大小和虛擬地址空間范圍。.
通過逐級查找和解析頁表項,操作系統(tǒng)可以將虛擬地址轉(zhuǎn)換為物理地址,并進行訪問控制和管理。因此,正確配置和使用頁表項對于有效管理內(nèi)存和實現(xiàn)安全性至關重要。
②各種類型的頁面
- Page Table Entry (PTE):記錄了一個頁面在物理內(nèi)存中的地址以及相關信息,用于虛擬地址到物理地址的映射。
- Page Global Directory (PGD):一種高級頁表結(jié)構(gòu),用于管理大量虛擬內(nèi)存。它將多個Page Table組織起來,形成更大的虛擬地址空間。
- Page Middle Directory (PMD):類似于PGD,但粒度更小。通常用于管理特定區(qū)域內(nèi)的虛擬內(nèi)存。
- Inverted Page Table (IPT):與傳統(tǒng)頁表不同,IPT根據(jù)物理地址索引每個頁面對應的虛擬地址和進程信息。它可以減少頁表占用的內(nèi)存,并提高查找效率。
- Translation Lookaside Buffer (TLB):高速緩存,位于CPU芯片上,加速虛擬地址到物理地址轉(zhuǎn)換過程。
(2)虛擬地址到物理地址的映射過程
虛擬地址到物理地址的映射過程是通過頁表完成的。在使用虛擬內(nèi)存時,操作系統(tǒng)將物理內(nèi)存劃分成固定大小的頁面(通常為4KB),并將每個進程的虛擬地址空間劃分成相同大小的頁面。
當程序訪問虛擬地址時,CPU會將該虛擬地址發(fā)送給內(nèi)存管理單元(MMU),其中包含一個頁表基址寄存器(Page Table Base Register, PTBR)指向當前進程的頁表。
映射過程如下:
- CPU將虛擬地址發(fā)送給MMU。
- MMU根據(jù)虛擬地址中的頁號找到對應的頁表項。
- 如果頁表項中標記為有效,則獲取對應的物理頁框號。
- 將物理頁框號與虛擬地址中的偏移量組合,得到最終的物理地址。
- 將最終物理地址返回給CPU,程序可以訪問該物理地址上存儲的數(shù)據(jù)。
如果在步驟3中發(fā)現(xiàn)頁表項無效,則表示所請求的頁面不在物理內(nèi)存中。這時可能觸發(fā)缺頁異常,操作系統(tǒng)需要從磁盤上加載對應頁面,并更新頁表項以建立新的映射關系。
1.3高速緩存(Cache):提升訪問速度的加速器
高速緩存(Cache)是提高內(nèi)存訪問速度的關鍵硬件組件,它利用了程序訪問的局部性原理,即程序在一段時間內(nèi)往往會頻繁訪問相同或相鄰的內(nèi)存區(qū)域 。Cache 通常分為多級,如 L1、L2 和 L3 Cache 。L1 Cache 速度最快,但容量最小,離 CPU 核心最近;L3 Cache 容量最大,但速度相對較慢 。當 CPU 需要訪問數(shù)據(jù)時,首先會在 L1 Cache 中查找,如果命中(找到所需數(shù)據(jù)),則可以快速獲取數(shù)據(jù),大大縮短訪問時間;如果未命中,則會依次到 L2、L3 Cache 以及主內(nèi)存中查找 。
例如,當 CPU 執(zhí)行一個循環(huán)讀取數(shù)組元素的操作時,由于數(shù)組元素在內(nèi)存中是連續(xù)存儲的,根據(jù)空間局部性原理,Cache 會將該數(shù)組附近的內(nèi)存塊一并加載進來,這樣在后續(xù)讀取數(shù)組元素時,就很可能在 Cache 中命中,從而提高訪問效率 。Cache 的替換算法(如最近最少使用 LRU 算法)決定了當 Cache 空間已滿時,哪些數(shù)據(jù)會被替換出去,以保證 Cache 中始終存儲著最常用的數(shù)據(jù) 。
TLB是一種高速緩存,內(nèi)存管理硬件使用它來改善虛擬地址到物理地址的轉(zhuǎn)換速度。當前所有的個人桌面,筆記本和服務器處理器都使用TLB來進行虛擬地址到物理地址的映射。使用TLB內(nèi)核可以快速的找到虛擬地址指向物理地址,而不需要請求RAM內(nèi)存獲取虛擬地址到物理地址的映射關系。這與data cache和instruction caches有很大的相似之處。
TLB的原理如下:
- 當CPU訪問一個虛擬地址時,首先檢查TLB中是否有對應的頁表項。
- 如果TLB中有對應的頁表項(即命中),則直接從TLB獲取物理地址。
- 如果TLB中沒有對應的頁表項(即未命中),則需要訪問內(nèi)存來獲取正確的頁表項。
- 在未命中情況下,操作系統(tǒng)會進行相應處理,從主存中獲取正確的頁表項,并將其加載到TLB中以供后續(xù)使用。
- 一旦正確的頁表項加載到TLB中,CPU再次訪問相同虛擬地址時就可以直接在TLB中找到映射關系,提高了轉(zhuǎn)換效率。
TLB具有快速查找和高效緩存機制,能夠極大地減少查詢頁表所需的時間。然而,由于TLB是有限容量的,在大型程序或多任務環(huán)境下可能無法完全覆蓋所有需要轉(zhuǎn)換的頁面。當發(fā)生TLB未命中時,則會導致額外的內(nèi)存訪問開銷;操作系統(tǒng)會負責管理和維護TLB,包括緩存策略、TLB的刷新機制等。常見的緩存策略有全相聯(lián)、組相聯(lián)和直接映射等。
二、內(nèi)存管理的硬件策略
2.1分頁機制:化整為零的智慧
在 Linux 的世界里,內(nèi)存分頁機制就像是一位有條不紊的大管家,精心管理著系統(tǒng)的內(nèi)存資源。簡單來說,內(nèi)存分頁機制就是把物理內(nèi)存和虛擬內(nèi)存分割成固定大小的小塊,這些小塊被稱作 “頁” ,每個頁的大小一般為 4KB 或者 8KB。就好比你有一個巨大的倉庫(內(nèi)存),為了更好地管理里面的貨物(數(shù)據(jù)),你把倉庫劃分成了一個個大小相同的小隔間(頁)。
圖片
分頁機制是 80x86 內(nèi)存管理機制的第二部分。它在分段機制的基礎上完成虛擬地址到物理地址的轉(zhuǎn)換過程。分段機制把邏輯地址轉(zhuǎn)換成線性地址,而分頁機制則把線性地址轉(zhuǎn)換成物理地址。分頁機制可用于任何一種分段模型。處理器分頁機制會把線性地址空間劃分成頁面,然后這些線性地址空間頁面被映射到物理地址空間的頁面上。分頁機制的幾種頁面級保護措施,可和分段機制保護措施或用或替代分段機制的保護措施。
(1)分頁機制如何啟用
在我們進行程序開發(fā)的時候,一般情況下,是不需要管理內(nèi)存的,也不需要操心內(nèi)存夠不夠用,其實,這就是分頁機制給我們帶來的好處。它是實現(xiàn)虛擬存儲的關鍵,位于線性地址與物理地址之間,在使用這種內(nèi)存分頁管理方法時,每個執(zhí)行中的進程(任務)可以使用比實際內(nèi)存容量大得多的連續(xù)地址空間。而且當系統(tǒng)內(nèi)存實際上被分成很多凌亂的塊時,它可以建立一個大而連續(xù)的內(nèi)存空間的映象,好讓程序不用操心和管理這些分散的內(nèi)存塊。分頁機制增強了分段機制的性能。頁地址變換是建立在段變換基礎之上的。因為,段管理機制對于Intel處理器來說是最基本的,任何時候都無法關閉。所以即使啟用了頁管理功能,分段機制依然是起作用的,段部件也依然工作。
分頁只能在保護模式(CR0.PE = 1)下使用。在保護模式下,是否開啟分頁,由 CR0. PG 位(位 31)決定:
- 當 CR0.PG = 0 時,未開啟分頁,線性地址等同于物理地址;
- 當 CR0.PG = 1 時,開啟分頁。
(2)分頁機制線性地址到物理地址轉(zhuǎn)換過程
80x86使用 4K 字節(jié)固定大小的頁面,每個頁面均是 4KB,并且對其于 4K 地址邊界處。這表示分頁機制把 2^32字節(jié)(4GB)的線性地址空間劃分成 2^20(1M = 1048576)個頁面。分頁機制通過把線性地址空間中的頁面重新定位到物理地址空間中進行操作。由于 4K 大小的頁面作為一個單元進行映射,并且對其于 4K 邊界,因此線性地址的低 12 位可做為頁內(nèi)偏移地量直接作為物理地址的低 12 位。分頁機制執(zhí)行的重定向功能可以看作是把線性地址的高 20 位轉(zhuǎn)換到對應物理地址的高 20 位。
線性到物理地址轉(zhuǎn)換功能,被擴展成允許一個線性地址被標注為無效的,而非要讓其產(chǎn)生一個物理地址。以下兩種情況一個頁面可以被標注為無效的:
- 1. 操作系統(tǒng)不支持的線性地址。
- 2. 對應的虛擬內(nèi)存系統(tǒng)中的頁面在磁盤上而非在物理內(nèi)存中。
在第一中情況下,產(chǎn)生無效地址的程序必須被終止,在第二種情況下,該無效地址實際上是請求 操作系統(tǒng)虛擬內(nèi)存管理器 把對應的頁面從磁盤加載到物理內(nèi)存中,以供程序訪問。因為無效頁面通常與虛擬存儲系統(tǒng)相關,因此它們被稱為不存在頁面,由頁表中稱為存在的屬性來確定。
當使用分頁時,處理器會把線性地址空間劃分成固定大小的頁面(4KB),這些頁面可以映射到物理內(nèi)存中或磁盤存儲空間中,當一個程序引用內(nèi)存中的邏輯地址時,處理器會把該邏輯地址轉(zhuǎn)換成一個線性地址,然后使用分頁機制把該線性地址轉(zhuǎn)換成對應的物理地址。
如果包含線性地址的頁面不在當前物理內(nèi)存中,處理器就會產(chǎn)生一個頁錯誤異常。頁錯誤異常處理程序就會讓操作系統(tǒng)從磁盤中把相應頁面加載到物理內(nèi)存中(操作過程中可能會把物理內(nèi)存中不同的頁面寫到磁盤上)。當頁面加載到物理內(nèi)存之后,從異常處理過程的返回操作會使異常的指令被重新執(zhí)行。處理器把用于線性地址轉(zhuǎn)換成物理地址和用于產(chǎn)生頁錯誤的信息包含在存儲與內(nèi)存中的頁目錄與頁表中。
2.2分段機制:各司其職的分工
分段機制則是根據(jù)程序的邏輯結(jié)構(gòu)將內(nèi)存劃分為不同的段,如代碼段、數(shù)據(jù)段、堆棧段等 。每個段都有自己的段基址和段界限 。邏輯地址由段號和段內(nèi)偏移組成 。當程序訪問內(nèi)存時,首先根據(jù)段號在段表中查找對應的段基址,然后將段基址與段內(nèi)偏移相加,得到物理地址 。例如,在 x86 架構(gòu)中,CS 寄存器存儲代碼段的段選擇子,DS 寄存器存儲數(shù)據(jù)段的段選擇子 。
當執(zhí)行一條指令時,會根據(jù) CS 寄存器中的段選擇子在段表中找到代碼段的段基址,再加上指令中的偏移地址,從而確定指令在內(nèi)存中的位置 。分段機制的優(yōu)點在于它更符合程序員的思維方式,便于程序的模塊化設計和共享 。比如,多個進程可以共享同一個代碼段,減少內(nèi)存的重復占用 。然而,分段機制也存在一些局限性,如容易產(chǎn)生外部碎片,內(nèi)存分配和管理相對復雜等 。
(1)段選擇子與段描述符
在理解了段的基本概念后,我們來看看段選擇子和段描述符,它們在分段機制中起著至關重要的作用。
段選擇子是一個 16 位的字段,它就像是一把鑰匙,雖然不能直接打開段這個 “房間”,但可以指向段描述符表中定義段的段描述符。段選擇子包含三個部分:13 位的索引值,它就像是圖書館書架上的編號,用來指定段描述符在全局描述符表(GDT)或局部描述符表(LDT)中的位置;1 位的表指示標志 TI,TI = 0 ,表示描述符在 GDT 中,TI = 1,表示描述符在 LDT 中,這就好比是告訴你要去哪個圖書館的書架找書;還有 2 位的請求特權(quán)級 RPL,它規(guī)定了訪問該段所需的特權(quán)級別,就像是進入某些特殊房間需要特定的權(quán)限一樣。
段描述符則是一個 8 字節(jié)的數(shù)據(jù)結(jié)構(gòu),它詳細地描述了段的各種特征,就像是一份關于房子的詳細說明書。段描述符中包含段基地址、段限長、段屬性等重要信息。其中,段基地址明確了段的起始物理地址;段限長決定了段的長度;段屬性則涵蓋了段的訪問權(quán)限(如可讀、可寫、可執(zhí)行等)、特權(quán)級等特性。通過段描述符,CPU 可以全面了解一個段的情況,從而進行正確的內(nèi)存訪問。
(2)邏輯地址到線性地址的轉(zhuǎn)換
在 Linux 內(nèi)核中,程序使用的是邏輯地址,而 CPU 訪問內(nèi)存時需要的是線性地址,因此就需要進行邏輯地址到線性地址的轉(zhuǎn)換,這個轉(zhuǎn)換過程是分段機制的核心。
當程序運行時,CPU 會遇到一個邏輯地址,它由段選擇子和段內(nèi)偏移量組成。為了將邏輯地址轉(zhuǎn)換為線性地址,CPU 會按照以下步驟進行操作:
- 查詢 GDT/LDT 表:CPU 首先會從段選擇子中提取出索引值和 TI 標志。如果 TI = 0,就表示要從全局描述符表 GDT 中查找段描述符;如果 TI = 1,則從局部描述符表 LDT 中查找。找到對應的描述符表后,根據(jù)索引值在表中定位到相應的段描述符,這就像是在圖書館的書架上找到了對應的書籍。
- 檢驗訪問權(quán)限和范圍:找到段描述符后,CPU 會檢查其中的段屬性,確認當前的訪問權(quán)限是否足夠,以及偏移量是否在段限長的范圍內(nèi)。比如,如果當前程序試圖寫入一個只讀的代碼段,就會因為權(quán)限不足而觸發(fā)異常;如果偏移量超出了段限長,也會被判定為非法訪問,同樣會觸發(fā)異常,這就像是沒有權(quán)限進入特殊房間或者超出了房間的活動范圍。
- 計算線性地址:在確認訪問合法后,CPU 會將段描述符中的段基地址與邏輯地址中的段內(nèi)偏移量相加,從而得到線性地址,這就像是找到了房間后,根據(jù)房間內(nèi)的具體位置信息找到了對應的物品。這個線性地址就是 CPU 在下一步進行內(nèi)存訪問時所使用的地址。
2.3虛擬內(nèi)存技術(shù):拓展內(nèi)存的魔法
虛擬內(nèi)存技術(shù)是利用磁盤空間來擴充物理內(nèi)存的一種神奇技術(shù) 。它使得程序可以使用比實際物理內(nèi)存更大的內(nèi)存空間 。其原理是將物理內(nèi)存和磁盤空間結(jié)合起來,操作系統(tǒng)將物理內(nèi)存劃分為固定大小的頁框,將虛擬內(nèi)存劃分為同樣大小的頁面 。當程序訪問的頁面不在物理內(nèi)存中時,就會觸發(fā)缺頁中斷 。操作系統(tǒng)會根據(jù)一定的頁置換算法(如最近最少使用 LRU 算法),選擇一個物理內(nèi)存中的頁面將其數(shù)據(jù)寫回磁盤,然后將程序需要的頁面從磁盤加載到物理內(nèi)存中 。
例如,當一個程序運行時,它可能會申請大量的內(nèi)存,但實際物理內(nèi)存有限 。此時,操作系統(tǒng)會將一些暫時不使用的頁面(如程序中很久未訪問的數(shù)據(jù)頁面)交換到磁盤上的交換文件(Page File)中,當程序再次需要這些頁面時,再從磁盤中讀取回來 。這樣,程序就可以在有限的物理內(nèi)存條件下運行,大大提高了系統(tǒng)的多任務處理能力和內(nèi)存的使用效率 。
(1)為什么需要使用虛擬內(nèi)存
進程需要使用的代碼和數(shù)據(jù)都放在內(nèi)存中,比放在外存中要快很多。問題是內(nèi)存空間太小了,不能滿足進程的需求,而且現(xiàn)在都是多進程,情況更加糟糕。所以提出了虛擬內(nèi)存,使得每個進程用于3G的獨立用戶內(nèi)存空間和共享的1G內(nèi)核內(nèi)存空間。(每個進程都有自己的頁表,才使得3G用戶空間的獨立)這樣進程運行的速度必然很快了。而且虛擬內(nèi)存機制還解決了內(nèi)存碎片和內(nèi)存不連續(xù)的問題。為什么可以在有限的物理內(nèi)存上達到這樣的效果呢?
為了更直觀地理解,我們可以把虛擬內(nèi)存想象成一個圖書館的目錄系統(tǒng)。每個進程就像是一個讀者,擁有自己的目錄(虛擬地址空間)。當讀者想要查找某本書(訪問數(shù)據(jù))時,會先在自己的目錄中找到對應的條目(虛擬地址),然后通過這個條目去書架(物理內(nèi)存)上找到實際的書。如果書架上沒有這本書(缺頁異常),圖書館管理員(操作系統(tǒng))就會從倉庫(磁盤)中把書取出來放到書架上,并更新目錄(頁表),以便下次讀者能更快地找到這本書。
例如:對于程序計數(shù)器位數(shù)為32位的處理器來說,他的地址發(fā)生器所能發(fā)出的地址數(shù)目為2^32=4G個,于是這個處理器所能訪問的最大內(nèi)存空間就是4G。在計算機技術(shù)中,這個值就叫做處理器的尋址空間或?qū)ぶ纺芰Α?/span>
照理說,為了充分利用處理器的尋址空間,就應按照處理器的最大尋址來為其分配系統(tǒng)的內(nèi)存。如果處理器具有32位程序計數(shù)器,那么就應該按照下圖的方式,為其配備4G的內(nèi)存:
圖片
這樣,處理器所發(fā)出的每一個地址都會有一個真實的物理存儲單元與之對應;同時,每一個物理存儲單元都有唯一的地址與之對應。這顯然是一種最理想的情況。
但遺憾的是,實際上計算機所配置內(nèi)存的實際空間常常小于處理器的尋址范圍,這是就會因處理器的一部分尋址空間沒有對應的物理存儲單元,從而導致處理器尋址能力的浪費。例如:如下圖的系統(tǒng)中,具有32位尋址能力的處理器只配置了256M的內(nèi)存儲器,這就會造成大量的浪費:
圖片
另外,還有一些處理器因外部地址線的根數(shù)小于處理器程序計數(shù)器的位數(shù),而使地址總線的根數(shù)不滿足處理器的尋址范圍,從而處理器的其余尋址能力也就被浪費了。例如:Intel8086處理器的程序計數(shù)器位32位,而處理器芯片的外部地址總線只有20根,所以它所能配置的最大內(nèi)存為1MB:
圖片
在實際的應用中,如果需要運行的應用程序比較小,所需內(nèi)存容量小于計算機實際所配置的內(nèi)存空間,自然不會出什么問題。但是,目前很多的應用程序都比較大,計算機實際所配置的內(nèi)存空間無法滿足。
實踐和研究都證明:一個應用程序總是逐段被運行的,而且在一段時間內(nèi)會穩(wěn)定運行在某一段程序里。
這也就出現(xiàn)了一個方法:如下圖所示,把要運行的那一段程序自輔存復制到內(nèi)存中來運行,而其他暫時不運行的程序段就讓它仍然留在輔存。
圖片
當需要執(zhí)行另一端尚未在內(nèi)存的程序段(如程序段2),如下圖所示,就可以把內(nèi)存中程序段1的副本復制回輔存,在內(nèi)存騰出必要的空間后,再把輔存中的程序段2復制到內(nèi)存空間來執(zhí)行即可:
圖片
在計算機技術(shù)中,把內(nèi)存中的程序段復制回輔存的做法叫做“換出”,而把輔存中程序段映射到內(nèi)存的做法叫做“換入”。經(jīng)過不斷有目的的換入和換出,處理器就可以運行一個大于實際物理內(nèi)存的應用程序了?;蛘哒f,處理器似乎是擁有了一個大于實際物理內(nèi)存的內(nèi)存空間。于是,這個存儲空間叫做虛擬內(nèi)存空間,而把真正的內(nèi)存叫做實際物理內(nèi)存,或簡稱為物理內(nèi)存。
那么對于一臺真實的計算機來說,它的虛擬內(nèi)存空間又有多大呢?計算機虛擬內(nèi)存空間的大小是由程序計數(shù)器的尋址能力來決定的。例如:在程序計數(shù)器的位數(shù)為32的處理器中,它的虛擬內(nèi)存空間就為4GB。
可見,如果一個系統(tǒng)采用了虛擬內(nèi)存技術(shù),那么它就存在著兩個內(nèi)存空間:虛擬內(nèi)存空間和物理內(nèi)存空間。虛擬內(nèi)存空間中的地址叫做“虛擬地址”;而實際物理內(nèi)存空間中的地址叫做“實際物理地址”或“物理地址”。處理器運算器和應用程序設計人員看到的只是虛擬內(nèi)存空間和虛擬地址,而處理器片外的地址總線看到的只是物理地址空間和物理地址。
由于存在兩個內(nèi)存地址,因此一個應用程序從編寫到被執(zhí)行,需要進行兩次映射。第一次是映射到虛擬內(nèi)存空間,第二次時映射到物理內(nèi)存空間。在計算機系統(tǒng)中,第兩次映射的工作是由硬件和軟件共同來完成的。承擔這個任務的硬件部分叫做存儲管理單元MMU,軟件部分就是操作系統(tǒng)的內(nèi)存管理模塊了。
在映射工作中,為了記錄程序段占用物理內(nèi)存的情況,操作系統(tǒng)的內(nèi)存管理模塊需要建立一個表格,該表格以虛擬地址為索引,記錄了程序段所占用的物理內(nèi)存的物理地址。這個虛擬地址/物理地址記錄表便是存儲管理單元MMU把虛擬地址轉(zhuǎn)化為實際物理地址的依據(jù),記錄表與存儲管理單元MMU的作用如下圖所示:
圖片
綜上所述,虛擬內(nèi)存技術(shù)的實現(xiàn),是建立在應用程序可以分成段,并且具有“在任何時候正在使用的信息總是所有存儲信息的一小部分”的局部特性基礎上的。它是通過用輔存空間模擬RAM來實現(xiàn)的一種使機器的作業(yè)地址空間大于實際內(nèi)存的技術(shù)。
從處理器運算裝置和程序設計人員的角度來看,它面對的是一個用MMU、映射記錄表和物理內(nèi)存封裝起來的一個虛擬內(nèi)存空間,這個存儲空間的大小取決于處理器程序計數(shù)器的尋址空間。
可見,程序映射表是實現(xiàn)虛擬內(nèi)存的技術(shù)關鍵,它可給系統(tǒng)帶來如下特點:
- 系統(tǒng)中每一個程序各自都有一個大小與處理器尋址空間相等的虛擬內(nèi)存空間;
- 在一個具體時刻,處理器只能使用其中一個程序的映射記錄表,因此它只看到多個程序虛存空間中的一個,這樣就保證了各個程序的虛存空間時互不相擾、各自獨立的;
- 使用程序映射表可方便地實現(xiàn)物理內(nèi)存的共享。
(2)虛擬內(nèi)存的頁、物理內(nèi)存的頁框及頁表
在Linux中,頁與頁框的大小一般為4KB。當然,根據(jù)系統(tǒng)和應用的不同,頁與頁框的大小也可有所變化。
物理內(nèi)存和虛擬內(nèi)存被分成了頁框與頁之后,其存儲單元原來的地址都被自然地分成了兩段,并且這兩段各自代表著不同的意義:高位段分別叫做頁框碼和頁碼,它們是識別頁框和頁的編碼;低位段分別叫做頁框偏移量和頁內(nèi)偏移量,它們是存儲單元在頁框和頁內(nèi)的地址編碼。下圖就是兩段虛擬內(nèi)存和物理內(nèi)存分頁之后的情況:
圖片
為了使系統(tǒng)可以正確的訪問虛存頁在對應頁框中的映像,在把一個頁映射到某個頁框上的同時,就必須把頁碼和存放該頁映像的頁框碼填入一個叫做頁表的表項中。這個頁表就是之前提到的映射記錄表。一個頁表的示意圖如下所示:
圖片
頁模式下,虛擬地址、物理地址轉(zhuǎn)換關系的示意圖如下所示:
圖片
也就是說:處理器遇到的地址都是虛擬地址。虛擬地址和物理地址都分成頁碼(頁框碼)和偏移值兩部分。在由虛擬地址轉(zhuǎn)化成物理地址的過程中,偏移值不變。而頁碼和頁框碼之間的映射就在一個映射記錄表——頁表中。
話說回來,內(nèi)存映射是 Linux 中一種重要的內(nèi)存管理技術(shù),它允許將一個文件或者其他對象映射到進程的虛擬地址空間中,使得進程可以像訪問內(nèi)存一樣直接訪問文件 。這種技術(shù)的核心優(yōu)勢在于提高了文件訪問的效率,減少了內(nèi)核和用戶空間之間的數(shù)據(jù)拷貝。在 Linux 中,內(nèi)存映射主要通過mmap()系統(tǒng)調(diào)用實現(xiàn)。
mmap()函數(shù)將文件或其他對象映射到虛擬地址空間的一個連續(xù)區(qū)域,返回一個指向映射區(qū)域開始地址的指針 。對該指針進行讀寫操作,實際上就是在訪問文件內(nèi)容。使用munmap()函數(shù)可以解除內(nèi)存映射。
三、硬件內(nèi)存管理的性能優(yōu)化
3.1硬件緩存優(yōu)化:突破速度瓶頸
隨著計算機技術(shù)的飛速發(fā)展,硬件緩存優(yōu)化成為提升內(nèi)存管理性能的關鍵方向。在多核處理器和多通道內(nèi)存控制器的協(xié)同作用下,緩存的并行性得到了極大提升 。以英特爾的酷睿 i9 系列處理器為例,其多核架構(gòu)使得多個核心可以同時訪問緩存,配合多通道內(nèi)存控制器,能夠顯著提高數(shù)據(jù)的讀寫速度 。當一個大型數(shù)據(jù)庫應用程序運行時,多核處理器的不同核心可以同時從緩存中讀取數(shù)據(jù),多通道內(nèi)存控制器則確保數(shù)據(jù)能夠快速地在內(nèi)存和緩存之間傳輸,從而加速數(shù)據(jù)庫的查詢操作 。
硬件壓縮技術(shù)也為緩存優(yōu)化帶來了新的思路 。通過在硬件層面實現(xiàn)數(shù)據(jù)壓縮和解壓縮,能夠有效減少內(nèi)存占用,提高緩存的利用率 。一些高端服務器采用了基于硬件的壓縮技術(shù),如英特爾的 QuickAssist Technology(QAT),可以對存儲在緩存中的數(shù)據(jù)進行實時壓縮 。當數(shù)據(jù)被寫入緩存時,硬件壓縮模塊會自動對數(shù)據(jù)進行壓縮,從而節(jié)省緩存空間;當數(shù)據(jù)被讀取時,再進行快速解壓縮 。這在處理大規(guī)模數(shù)據(jù)時,能夠顯著提高緩存的命中率,減少對主內(nèi)存的訪問次數(shù),進而提升系統(tǒng)性能 。
新型非易失性內(nèi)存(NVM)的出現(xiàn),為緩存性能的提升提供了新的可能 。相變存儲器(PCM)、磁阻隨機存取存儲器(MRAM)等新型 NVM 具有非易失性、高存儲密度和低功耗等優(yōu)點 。將這些新型 NVM 應用于緩存中,可以實現(xiàn)更快的數(shù)據(jù)訪問速度和更高的緩存容量 。例如,三星的基于 PCM 的緩存技術(shù),在斷電時數(shù)據(jù)不會丟失,并且能夠快速地響應讀寫請求,大大提高了系統(tǒng)的穩(wěn)定性和性能 。
3.2大頁內(nèi)存管理:提升效率的新途徑
大頁內(nèi)存管理作為一種新興的內(nèi)存管理技術(shù),正逐漸在高性能計算領域嶄露頭角 。其原理是使用更大的頁大?。ㄈ?2MB 或 1GB)來替代傳統(tǒng)的 4KB 頁大小,從而減少頁表項的數(shù)量,優(yōu)化內(nèi)存訪問性能 。以數(shù)據(jù)庫管理系統(tǒng)為例,如 Oracle 數(shù)據(jù)庫,在處理大規(guī)模數(shù)據(jù)時,使用大頁內(nèi)存可以顯著減少頁表的開銷 。由于大頁內(nèi)存的頁表項數(shù)量大幅減少,數(shù)據(jù)庫在進行數(shù)據(jù)查詢時,地址轉(zhuǎn)換的時間大大縮短,從而提高了查詢性能 。在一個擁有 128GB 內(nèi)存的數(shù)據(jù)庫服務器中,使用 4KB 頁大小可能會產(chǎn)生數(shù)百萬個頁表項,而使用 2MB 大頁內(nèi)存,頁表項數(shù)量可以減少到原來的千分之一,這使得數(shù)據(jù)庫的內(nèi)存管理更加高效 。
在虛擬化場景里,大頁內(nèi)存管理的價值同樣不可忽視。以主流的 VMware ESXi 虛擬化平臺為例,它對大頁內(nèi)存提供完善支持,這一特性能直接降低虛擬機運行過程中的內(nèi)存管理開銷。要知道,虛擬機與宿主機之間的上下文切換,往往伴隨著一系列復雜的內(nèi)存管理操作,而大頁內(nèi)存可有效簡化這些流程 —— 通過減少上下文切換所需的時間,直接為虛擬機性能提升提供助力。尤其在運行多臺虛擬機的服務器中,當每臺虛擬機都啟用大頁內(nèi)存后,不僅能顯著減少內(nèi)存碎片問題,讓內(nèi)存資源的利用率得到優(yōu)化,還能從整體上進一步提升所有虛擬機的運行性能,為多負載虛擬化環(huán)境提供更穩(wěn)定高效的內(nèi)存支撐。


























