目錄
虛擬位址" >虛擬位址
虛擬位址的好處" >虛擬位址的好處
物理位址" >物理位址
ZONE_DMA" >ZONE_DMA
ZONE_NORMAL" >ZONE_NORMAL
ZONE_HIGHMEM" >ZONE_HIGHMEM
使用者空間" >使用者空間
進程與記憶體" >進程與記憶體
核心空間" >核心空間
直接對映區" >直接對映區
高階記憶體線性位址空間" >高階記憶體線性位址空間
動態記憶體映射區" >動態記憶體映射區
永久記憶體映射區" >永久記憶體映射區
固定映射區" >固定映射區
回顧一下" >回顧一下
記憶體資料結構" >記憶體資料結構
使用者空間記憶體資料結構" >使用者空間記憶體資料結構
核心空間動態分配記憶體資料結構" >核心空間動態分配記憶體資料結構
總結一下" >總結一下
首頁 系統教程 Linux 別再說你不懂Linux記憶體管理了,10張圖給你安排的明明白白!

別再說你不懂Linux記憶體管理了,10張圖給你安排的明明白白!

Feb 10, 2024 pm 11:48 PM
linux linux教程 linux系統 linux指令 shell腳本 linux入門 linux學習

今天我們來研究一下 Linux 的記憶體管理。

對於精通 CURD 的業務同學來說,記憶體管理似乎離我們很遠。但這個知識點雖然冷門(估計很多人學完後根本用不上),但它絕對是基礎中的基礎。

這就像武俠小說中的內功修煉,學完後看不到立竿見影的效果,但對你日後的開發工作大有裨益,因為你站得更高了。

文中所有範例圖都是我親手畫的。畫圖比碼字還花時間,但大家看圖理解比文字更直觀,所以還是畫了。需要高畫質範例圖片的同學,文末有取得方式自取。

再功利地說,如果在面試時不經意間透露你懂這方面的知識,並能說出個一二三來,也許能讓面試官對你更感興趣,離升職加薪、走上人生巔峰又更近了一步。

前提約定:本文討論技術內容的前提是作業系統環境都是 x86 架構的 32 位元 Linux 系統。

虛擬位址

#即使在現代作業系統中,記憶體仍然是電腦中非常寶貴的資源。看看你電腦幾個 T 的固態硬碟,再看看記憶體大小就知道了。

為了充分利用和管理系統記憶體資源,Linux 採用虛擬記憶體管理技術。利用虛擬記憶體技術,每個行程都擁有 4GB 互不干涉的虛擬位址空間。

進程初始化分配和操作都是基於這個「虛擬位址」。只有當進程需要實際存取記憶體資源時才會建立虛擬位址和實體位址的映射,並調入實體記憶體頁。

打個不太恰當的比方,這個原理其實跟現在的某某網盤一樣。假如你的網盤空間是 1TB,真以為就一口氣給了你這麼大空間嗎?那還是太年輕了。都是在你往裡面放東西時才給你分配空間,放多少就分多少實際空間給你。但你和你朋友看起來就像大家都擁有 1TB 空間一樣。

虛擬位址的好處

  • # 避免使用者直接存取實體記憶體位址,防止破壞性操作,保護作業系統。
  • 每個進程都被分配了 4GB 的虛擬內存,用戶程式可以使用比實際物理內存更大的位址空間。

4GB 的進程虛擬位址空間被分成兩部分:「用戶空間」和「核心空間」。

別再說你不懂Linux記憶體管理了,10張圖給你安排的明明白白!

使用者空間核心空間

物理位址

上面章節我們已經知道不管是使用者空間還是核心空間,使用的位址都是虛擬位址,當需進程要實際存取記憶體的時候,會由核心的「請求分頁機制」產生「缺頁異常」調入實體記憶體頁。

把虛擬位址轉換成記憶體的實體位址,這中間涉及利用MMU 記憶體管理單元(Memory Management Unit ) 對虛擬位址分段和分頁(段頁式)位址轉換,關於分段和分頁的具體流程,這裡不再贅述,可以參考任何一本電腦組成原理教材描述。

別再說你不懂Linux記憶體管理了,10張圖給你安排的明明白白!

段頁式記憶體管理位址轉換

Linux 核心會將實體記憶體分成3個管理區,分別是:

ZONE_DMA

#DMA記憶體區域。包含0MB~16MB之間的記憶體頁框,可以由老式基於ISA的裝置透過DMA使用,直接對應到核心的位址空間。

ZONE_NORMAL

普通記憶體區域。包含16MB~896MB之間的記憶體頁框,常規頁框,直接映射到核心的位址空間。

ZONE_HIGHMEM

高階記憶體區域。包含896MB以上的記憶體頁框,不進行直接映射,可以透過永久映射和暫時映射進行這部分記憶體頁框的存取。

別再說你不懂Linux記憶體管理了,10張圖給你安排的明明白白!

物理記憶體區劃分

使用者空間

用戶進程能存取的是「用戶空間」,每個進程都有自己獨立的用戶空間,虛擬位址範圍從從0x000000000xBFFFFFFF 總容量3G 。

使用者程序通常只能存取使用者空間的虛擬位址,只有在執行內陷操作或系統呼叫時才能存取核心空間。

進程與記憶體

#進程(執行的程式)佔用的使用者空間依照「 存取屬性一致的位址空間存放在一起 」的原則,劃分成 5個不同的記憶體區域。存取屬性指的是「可讀、可寫入、可執行等 。

  • 程式碼片段

    程式碼片段是用來存放可執行檔的操作指令,可執行程式在記憶體中的鏡像。程式碼段需要防止在運行時被非法修改,所以只準許讀取操作,它是不可寫的。

  • 資料段

    資料段用來存放可執行檔中已初始化全域變量,換句話說就是存放程式靜態分配的變數和全域變數。

  • BSS段

    BSS段包含了程式中未初始化的全域變量,在記憶體中 bss 段全部置零。

  • heap

    #

    堆是用來存放進程運行中被動態分配的記憶體段,它的大小並不固定,可動態擴張或縮減。當進程呼叫malloc等函數分配記憶體時,新分配的記憶體就被動態加入到堆上(堆被擴張);當利用free等函數釋放記憶體時,被釋放的記憶體從堆中被剔除(堆被縮減)

  • 堆疊 stack

    #堆疊是使用者存放程式暫時建立的局部變量,也就是函數中定義的變數(但不包含 static 宣告的變量,static意味著在資料段中存放變數)。除此之外,在函數被​​呼叫時,其參數也會被壓入發起呼叫的進程棧中,並且待到呼叫結束後,函數的回傳值也會被存放回棧中。由於棧的先進後出特點,所以棧特別方便用來保存/恢復呼叫現場。從這個意義上講,我們可以把堆疊看成一個寄存、交換臨時資料的記憶體區。

上述幾種記憶體區域中資料段、BSS 段、堆通常是被連續儲存在記憶體中,在位置上是連續的,而程式碼段和堆疊往往會被獨立存放。堆疊和堆疊兩個區域在 i386 體系結構中堆疊向下擴展、堆疊向上擴展,相對而生。 別再說你不懂Linux記憶體管理了,10張圖給你安排的明明白白!

你也可以在linux下用size 指令查看編譯後程式的各個記憶體區域大小:

[lemon ~]# size /usr/local/sbin/sshd
   text   data    bss    dec    hexfilename
1924532  12412 4268962363840 2411c0/usr/local/sbin/sshd
登入後複製

核心空間

x86 32 位元系統裡,Linux 核心位址空間是指虛擬位址從0xC0000000 開始到0xFFFFFFFF 為止的高階記憶體位址空間,總計1G 的容量, 包括了核心鏡像、實體頁面表、驅動程式等運行在核心空間。

別再說你不懂Linux記憶體管理了,10張圖給你安排的明明白白!

核心空間細分區域.

直接對映區

#直接映射區 Direct Memory Region:從核心空間起始位址開始,最大896M的核心空間位址區間,為直接記憶體映射區。

直接映射區的896MB的「線性位址」直接與「物理位址」的前896MB進行映射,也就是說線性位址和分配的物理位址都是連續的。核心位址空間的線性位址0xC0000001所對應的實體位址為0x00000001,它們之間相差一個偏移量PAGE_OFFSET = 0xC0000000

#該區域的線性位址和實體位址存在線性轉換關係「線性位址= PAGE_OFFSET 實體位址」也可以用virt_to_phys()函數將核心虛擬空間中的線性位址轉換為實體地址。

高階記憶體線性位址空間

#核心空間線性位址從 896M 到 1G 的區間,容量 128MB 的位址區間是高階記憶體線性位址空間,為什麼叫高階記憶體線性位址空間?下面給你解釋一下:

前面已經說過,核心空間的總大小 1GB,從核心空間起始位址開始的 896MB 的線性位址可以直接對應到實體位址大小為 896MB 的位址區間。

退一萬步,即使核心空間的1GB線性位址都會對應到實體位址,那也最多只能尋址 1GB 大小的實體記憶體位址範圍。

請問你現在你家的記憶體有多大?快醒都 2023 年了,一般 PC 的記憶體都大於 1GB 了吧!

所以,核心空間拿出了最後的 128M 位址區間,劃分成下面三個高階記憶體映射區,以達到整個實體位址範圍的尋址。而在 64 位元的系統上就不存在這樣的問題了,因為可用的線性位址空間遠大於可安裝的記憶體。

動態記憶體映射區

#vmalloc Region 此區域由核心函數vmalloc來分配,特點是:線性空間連續,但對應的實體位址空間不一定連續。 vmalloc 分配的線性位址所對應的物理頁可能處於低階內存,也可能處於高階記憶體。

永久記憶體映射區

#Persistent Kernel Mapping Region 此區域可存取高階記憶體。存取方法是使用 alloc_page (_GFP_HIGHMEM) 分配高階記憶體頁或使用kmap函數將分配到的高階記憶體對應到該區域。

固定映射區

#Fixing kernel Mapping Region 該區域和 4G 的頂端只有 4k 的隔離帶,其每個位址項目都服務於特定的用途,如 ACPI_BASE 等。

別再說你不懂Linux記憶體管理了,10張圖給你安排的明明白白!

核心空間物理記憶體映射

回顧一下

上面講的有點多,先別急著進入下一節,在這之前我們再來回顧一下上面所講的內容。如果認真看完上面的章節,我這裡再畫了一張圖,現在你的腦海中應該會有這樣一個記憶體管理的全域圖。

別再說你不懂Linux記憶體管理了,10張圖給你安排的明明白白!

核心空間使用者空間全圖

記憶體資料結構

#要讓核心管理系統中的虛擬內存,必然要從中抽像出內存管理資料結構,內存管理操作如“分配、釋放等”都基於這些數據結構操作,這裡列舉兩個管理虛擬內存區域的數據結構。

使用者空間記憶體資料結構

#在前面「進程與記憶體」章節我們提到,Linux進程可以分割為5 個不同的記憶體區域,分別是:程式碼段、資料段、BSS、堆疊、堆疊,核心管理這些區域的方式是,將這些記憶體區域抽象化為vm_area_struct的記憶體管理物件。

vm_area_struct是描述行程位址空間的基本管理單元,一個行程往往需要多個vm_area_struct來描述它的使用者空間虛擬位址,需要使用「鍊錶」和「紅黑樹」來組織各個vm_area_struct

鍊錶用於需要遍歷全部節點的時候用,而紅黑樹適用於在位址空間中定位特定記憶體區域。核心為了記憶體區域上的各種不同操作都能獲得高效能,所以同時使用了這兩種資料結構。

使用者空間程序的位址管理模型:

別再說你不懂Linux記憶體管理了,10張圖給你安排的明明白白!

wm_arem_struct

#

核心空間動態分配記憶體資料結構

在核心空間章節我們提到「動態記憶體映射區」,該區域由內核函數vmalloc來分配,特點是:線性空間連續,但是對應的物理位址空間不一定連續。 vmalloc 分配的線性位址所對應的物理頁可能處於低階內存,也可能處於高階記憶體。

vmalloc 指派的位址則限於vmalloc_startvmalloc_end之間。每一塊vmalloc分配的核心虛擬記憶體都對應一個vm_struct結構體,不同的核心空間虛擬位址之間有4k大小的防越界空閒區間隔區。

與使用者空間的虛擬位址特性一樣,這些虛擬位址與實體記憶體沒有簡單的映射關係,必須透過核心頁表才可轉換為實體位址或實體頁,它們有可能尚未被映射,當發生缺頁時才真正分配實體頁面。

別再說你不懂Linux記憶體管理了,10張圖給你安排的明明白白!

動態記憶體映射

總結一下

Linux記憶體管理是一個非常複雜的系統,本文所述只是冰山一角,從宏觀角度給你展現記憶體管理的全貌,但一般來說,這些知識在你和麵試官聊天的時候還是夠用的,當然也希望大家能透過閱讀了解更深層的原理。

本文可以作為一個索引一樣的學習指南,當你想深入某一點學習的時候可以在這些章節裡找到切入點,以及這個知識點在記憶體管理宏觀上的位置。

本文創作過程我也畫了大量的示例圖解,可以作為知識索引,個人感覺看圖還是比看文字更清晰明了,你可以在我公眾號“後端技術學堂”後台回复“記憶體管理」取得這些圖片的高清原圖。

老規矩,感謝各位的閱讀,文章的目的是分享對知識的理解,技術類文章我都會反复求證以求最大程度保證準確性,若文中出現明顯紕漏也歡迎指出,我們一起在探討中學習。今天的技術分享就到這裡,我們下期再見。

以上是別再說你不懂Linux記憶體管理了,10張圖給你安排的明明白白!的詳細內容。更多資訊請關注PHP中文網其他相關文章!

本網站聲明
本文內容由網友自願投稿,版權歸原作者所有。本站不承擔相應的法律責任。如發現涉嫌抄襲或侵權的內容,請聯絡admin@php.cn

熱AI工具

Undresser.AI Undress

Undresser.AI Undress

人工智慧驅動的應用程序,用於創建逼真的裸體照片

AI Clothes Remover

AI Clothes Remover

用於從照片中去除衣服的線上人工智慧工具。

Undress AI Tool

Undress AI Tool

免費脫衣圖片

Clothoff.io

Clothoff.io

AI脫衣器

Video Face Swap

Video Face Swap

使用我們完全免費的人工智慧換臉工具,輕鬆在任何影片中換臉!

熱工具

記事本++7.3.1

記事本++7.3.1

好用且免費的程式碼編輯器

SublimeText3漢化版

SublimeText3漢化版

中文版,非常好用

禪工作室 13.0.1

禪工作室 13.0.1

強大的PHP整合開發環境

Dreamweaver CS6

Dreamweaver CS6

視覺化網頁開發工具

SublimeText3 Mac版

SublimeText3 Mac版

神級程式碼編輯軟體(SublimeText3)

vscode需要什麼電腦配置 vscode需要什麼電腦配置 Apr 15, 2025 pm 09:48 PM

VS Code 系統要求:操作系統:Windows 10 及以上、macOS 10.12 及以上、Linux 發行版處理器:最低 1.6 GHz,推薦 2.0 GHz 及以上內存:最低 512 MB,推薦 4 GB 及以上存儲空間:最低 250 MB,推薦 1 GB 及以上其他要求:穩定網絡連接,Xorg/Wayland(Linux)

Linux體系結構:揭示5個基本組件 Linux體系結構:揭示5個基本組件 Apr 20, 2025 am 12:04 AM

Linux系統的五個基本組件是:1.內核,2.系統庫,3.系統實用程序,4.圖形用戶界面,5.應用程序。內核管理硬件資源,系統庫提供預編譯函數,系統實用程序用於系統管理,GUI提供可視化交互,應用程序利用這些組件實現功能。

vscode終端使用教程 vscode終端使用教程 Apr 15, 2025 pm 10:09 PM

vscode 內置終端是一個開發工具,允許在編輯器內運行命令和腳本,以簡化開發流程。如何使用 vscode 終端:通過快捷鍵 (Ctrl/Cmd ) 打開終端。輸入命令或運行腳本。使用熱鍵 (如 Ctrl L 清除終端)。更改工作目錄 (如 cd 命令)。高級功能包括調試模式、代碼片段自動補全和交互式命令歷史。

git怎麼查看倉庫地址 git怎麼查看倉庫地址 Apr 17, 2025 pm 01:54 PM

要查看 Git 倉庫地址,請執行以下步驟:1. 打開命令行並導航到倉庫目錄;2. 運行 "git remote -v" 命令;3. 查看輸出中的倉庫名稱及其相應的地址。

notepad怎麼運行java代碼 notepad怎麼運行java代碼 Apr 16, 2025 pm 07:39 PM

雖然 Notepad 無法直接運行 Java 代碼,但可以通過借助其他工具實現:使用命令行編譯器 (javac) 編譯代碼,生成字節碼文件 (filename.class)。使用 Java 解釋器 (java) 解釋字節碼,執行代碼並輸出結果。

vscode在哪寫代碼 vscode在哪寫代碼 Apr 15, 2025 pm 09:54 PM

在 Visual Studio Code(VSCode)中編寫代碼簡單易行,只需安裝 VSCode、創建項目、選擇語言、創建文件、編寫代碼、保存並運行即可。 VSCode 的優點包括跨平台、免費開源、強大功能、擴展豐富,以及輕量快速。

Linux的主要目的是什麼? Linux的主要目的是什麼? Apr 16, 2025 am 12:19 AM

Linux的主要用途包括:1.服務器操作系統,2.嵌入式系統,3.桌面操作系統,4.開發和測試環境。 Linux在這些領域表現出色,提供了穩定性、安全性和高效的開發工具。

vscode終端命令不能用 vscode終端命令不能用 Apr 15, 2025 pm 10:03 PM

VS Code 終端命令無法使用的原因及解決辦法:未安裝必要的工具(Windows:WSL;macOS:Xcode 命令行工具)路徑配置錯誤(添加可執行文件到 PATH 環境變量中)權限問題(以管理員身份運行 VS Code)防火牆或代理限制(檢查設置,解除限制)終端設置不正確(啟用使用外部終端)VS Code 安裝損壞(重新安裝或更新)終端配置不兼容(嘗試不同的終端類型或命令)特定環境變量缺失(設置必要的環境變量)

See all articles