目錄
一、物理地址空間是什么?
二、物理地址空間的構成:不僅僅是內存
三、Linux內核如何管理物理地址空間
(1)物理內存的碎片化問題
(2)物理地址的分區管理
(3)物理地址與內核的直接映射
四、物理地址和虛擬地址的關系? ?
一、物理地址空間是什么?
? ? ? ? 對于剛剛接觸Linux的新手而言,物理地址空間是理解內存的第一道門檻。他是硬件與內核交互的核心紐帶,也是程序最終運行時候的真實地點。
? ? ? ? 簡單來說,物理地址空間是硬件層面的“內存地圖”,他主要是由cpu和內存控制器定義的,可以直接訪問的地址范圍。就好比有許多個格子,每一個編號對應一個格子,這個編號就是物理地址。
? ? ? ? 物理地址空間有兩個關鍵特性:
(1)硬件決定性:地址范圍由CPU位數和內存控制器決定。比如32位CPU理論上最大支持4GB的物理地址空間,因為他有32根地址線,2^32次方剛好對應4GB的編號。而64位CPU目前理論值遠超實際硬件的地址范圍,主流硬件支持48位物理地址,即256TB。
(2)直接關聯性:物理地址直接對應硬件存儲單元,CPU可以通過物理地址直接訪問這些硬件資源,而不需要額外的地址轉換或映射。(因為許多硬件廠家就預定了物理地址范圍,即CPU只能去這些地址訪問,否則硬件識別不了)
二、物理地址空間的構成:不僅僅是內存
? ? ? ? 很多人在學習的時候,會誤認為物理地址空間僅僅對應我們插在主板上的內存條,但實際上他包含了計算機中所有需要通過硬件訪問的硬件資源,主要分為以下幾類:
(1)DRAM動態隨機存取存儲器:就是我們平常說的內存,是物理地址空間中最為核心的部分,用于臨時存放程序的數據和程序。他的特點是可讀可寫,速度快,掉電丟失。
(2)ROM/Flash:用于存儲固件程序(如BIOS、UEFI等)在計算機啟動的時候,CPU會從ROM的固定物理地址開始執行程序(在計算機啟動的時候,CPU還沒有加載操作系統,它不知道自己應該從哪里開始執行,所以必須預設一個固定地址,從這里開始初始化硬件,并加載操作系統)。這部分地址通常是只可讀的(或者在燒錄的時候可寫)
(3)外設地址空間:計算機的顯卡、網卡等外設。他們的控制寄存器和數據緩沖區也會被映射到物理地址空間中。例如CPU向網卡發送數據的時候,實際上是向物理地址空間的某個特定地址寫入數據。
????????雖然他們都是物理地址空間的構成部分,但是我們說了CPU由于地址線的限制,比如32位CPU只能尋址到4GB空間,所以他們一定是屬于這4GB的一部分。
? ? ? ? 當然我們這里說的是內存映射方式,至于IO映射方式不在物理地址空間的4GB中,我們更多使用的是內存映射,這里不再討論IO映射。
為什么硬件必須有自己廠商固定好的地址?
? ? ? ? 其一,在早期沒有操作系統的時候,不存在虛擬地址空間、頁表等說法,所以CPU在執行的時候直接操作的就是物理地址(比如單片機)。但是各個硬件設備如果沒有規定好的地址范圍,可能網卡、和鍵盤起沖突了,都規定在了同樣的地址上,那么此時CPU訪問該物理地址就不知道是誰了。所以形成了一種約定,什么設備應該放在什么地址,如果不遵守這個規則,CPU就無法通過BIOS程序寫死的地址中找到對應的硬件設備。
????????其二,CPU在上電之后會執行BIOS程序,在這個程序之中,首先要做的就是硬件檢測,看看這些硬件設備能不能正常運行,有沒有哪里損壞。這個過程中還沒有加載操作系統,所以不可能存在虛擬地址以及頁表的概念。之后才會進行硬件初始化,加載引導程序開始加載操作系統,并將控制權從BIOS交給操作系統。
? ? ? ? 但并非所有的硬件都是CPU直接通過物理地址訪問(雖然硬件只認物理地址)。一般對于需要快速響應的設別,CPU會直接通過物理地址的對應設備的寄存器其訪問,減少了頁表這一層轉換,提高了效率。
? ? ? ? 然而對于大塊硬件資源(啟動的時候仍然是通過物理地址),如顯卡的顯存、網卡的緩沖區,因為對于大量的數據信息,可能該設備的寄存器根本不夠用,比如要渲染某個游戲畫面,往往需要幾個GB的數據。
????????操作系統會給這些物理地址分配一個虛擬地址,然后通過頁表映射到實際物理地址。這樣做的好處是應用程序不需要知道物理地址,只需要操作虛擬地址,且操作系統可以通過頁表權限控制防止應用程序錯誤修改硬件資源。
三、Linux內核如何管理物理地址空間
????????物理地址是硬件資源,而操作系統的任務就是高效、安全的管理這些資源。其管理邏輯主要圍繞著以下幾個關鍵點展開:
(1)物理內存的碎片化問題
? ? ? ? 物理內存由連續的頁框(通常為4kb)組成,就好像一張張A4紙,每次使用和回收的時候,由MMU內存管理單元一頁一頁的分配,但是實際軟件的數據可能并不存放在一張A4紙中,即兩張各存一部分。如果頻繁的申請內存以及釋放,就會導致碎片問題,即存在大量的頁都被一部分小數據占用,就好像每張A4紙寫幾個孤零零的字,由于他們已經被使用了,所以不能被回收成完整的大頁。也就是不能申請很大的連續空間,比如1MB的連續空間。
? ? ? ? 為了解決這個問題,Linux內核采用伙伴系統來管理空閑頁。就和我們之前做過的一個項目tcmalloc類似的內存池技術類似。
(1)把空閑頁按照1、2、4、8這種形式分組,每一組稱為一個伙伴塊。
(2)當需要分配 n 頁內存時,尋找最小的、大于等于 n 的伙伴塊,若塊過大則拆分;釋放時若相鄰塊空閑則合并。
(2)物理地址的分區管理
????????內核會將物理地址劃分為不同的區域,針對不同區域采取不同的管理策略
(1)ZONE_DMA:直接內存訪問(DMA)區域,地址范圍較低(通常 16MB 以下),供需要 DMA 傳輸的外設使用(如老式硬盤控制器)。
(2)ZONE_HIGHMEM:高端內存區域(32 位系統中超過 896MB 的部分),內核不能直接映射,需要通過臨時映射機制訪問(64 位系統因地址空間充足,通常無需此區域)。
之所以直接的線性映射區只有896MB,是因為剩余的128MB需要留給其他用途,如映射IO設備的物理地址、內核自身的代碼數據等。
(3)ZONE_NORMAL:常規可直接映射區域,內核可以直接訪問的物理內存(32 位系統中通常為 1GB 左右)。常規映射區域是給內核使用的,內核范圍是3GB-4GB。所以這部分的虛擬地址=物理地址0-896MB+3GB。
(3)物理地址與內核的直接映射
????????Linux 內核自身需要快速訪問物理內存,因此會將物理地址空間的一部分(通常是 ZONE_DMA 和 ZONE_NORMAL)直接線性映射到內核虛擬地址空間中。例如,物理地址 0x100000 會被映射到內核虛擬地址 0xC0100000(32 位系統)(物理地址增加3GB),這種映射是固定的、一對一的,內核通過簡單的地址計算就能訪問物理內存,無需復雜的頁表查詢。
四、物理地址和虛擬地址的關系? ?
- 物理地址空間是 “倉庫的真實貨架編號”,每個編號對應唯一的貨架位置,倉庫管理員(內核)必須知道它才能找到貨物。?
- 虛擬地址空間是 “給客戶的取貨編號”,客戶(用戶程序)只需要記住這個編號,無需關心貨物實際放在哪個貨架。?
- 即客戶來取貨的時候,只能通過倉庫管理員。而倉庫管理員掌握了一張頁表,知道用戶取貨編號和倉庫真實編號的映射關系。
兩者的映射關系由內核通過頁表維護:用戶程序使用虛擬地址訪問內存時,CPU 的內存管理單元(MMU)會根據頁表將虛擬地址轉換為物理地址,最終訪問實際的硬件內存。這種機制的好處是:?
- 隔離進程:每個進程都有獨立的虛擬地址空間,互不干擾。?
- 靈活利用內存:即使物理內存不足,也能通過 swap 分區(虛擬內存)暫時存儲數據。?
- 安全性:用戶程序無法直接訪問物理地址,防止惡意程序破壞系統。