面試問了解Linux內存管理嗎?10張圖給你安排得明明白白!

2020-12-18 計算機java編程

今天來帶大家研究一下Linux內存管理。對於精通 CURD 的業務同學,內存管理好像離我們很遠,但這個知識點雖然冷門(估計很多人學完根本就沒機會用上)但絕對是基礎中的基礎,這就像武俠中的內功修煉,學完之後看不到立竿見影的效果,但對你日後的開發工作是大有裨益的,因為你站的更高了。

文中所有示例圖都是我親手畫的,畫圖比碼字還費時間,但是看圖理解比文字更直觀,需要高清示例圖片的同學,文末有獲取方式自取。

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

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

虛擬地址

即使是現代作業系統中,內存依然是計算機中很寶貴的資源,看看你電腦幾個T固態硬碟,再看看內存大小就知道了。為了充分利用和管理系統內存資源,Linux採用虛擬內存管理技術,利用虛擬內存技術讓每個進程都有4GB 互不幹涉的虛擬地址空間。

進程初始化分配和操作的都是基於這個「虛擬地址」,只有當進程需要實際訪問內存資源的時候才會建立虛擬地址和物理地址的映射,調入物理內存頁。

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

虛擬地址的好處

避免用戶直接訪問物理內存地址,防止一些破壞性操作,保護作業系統每個進程都被分配了4GB的虛擬內存,用戶程序可使用比實際物理內存更大的地址空間4GB 的進程虛擬地址空間被分成兩部分:「用戶空間」和「內核空間」

物理地址

上面章節我們已經知道不管是用戶空間還是內核空間,使用的地址都是虛擬地址,當需進程要實際訪問內存的時候,會由內核的「請求分頁機制」產生「缺頁異常」調入物理內存頁。

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

Linux 內核會將物理內存分為3個管理區,分別是:

ZONE_DMA

DMA內存區域。包含0MB~16MB之間的內存頁框,可以由老式基於ISA的設備通過DMA使用,直接映射到內核的地址空間。

ZONE_NORMAL

普通內存區域。包含16MB~896MB之間的內存頁框,常規頁框,直接映射到內核的地址空間。

ZONE_HIGHMEM

高端內存區域。包含896MB以上的內存頁框,不進行直接映射,可以通過永久映射和臨時映射進行這部分內存頁框的訪問。

用戶空間

用戶進程能訪問的是「用戶空間」,每個進程都有自己獨立的用戶空間,虛擬地址範圍從從 0x00000000 至 0xBFFFFFFF 總容量3G 。

用戶進程通常只能訪問用戶空間的虛擬地址,只有在執行內陷操作或系統調用時才能訪問內核空間。

進程與內存

進程(執行的程序)佔用的用戶空間按照「 訪問屬性一致的地址空間存放在一起 」的原則,劃分成 5個不同的內存區域。 訪問屬性指的是「可讀、可寫、可執行等 。

代碼段代碼段是用來存放可執行文件的操作指令,可執行程序在內存中的鏡像。代碼段需要防止在運行時被非法修改,所以只準許讀取操作,它是不可寫的。數據段數據段用來存放可執行文件中已初始化全局變量,換句話說就是存放程序靜態分配的變量和全局變量。BSS段BSS段包含了程序中未初始化的全局變量,在內存中 bss 段全部置零。heap堆是用於存放進程運行中被動態分配的內存段,它的大小並不固定,可動態擴張或縮減。當進程調用malloc等函數分配內存時,新分配的內存就被動態添加到堆上(堆被擴張);當利用free等函數釋放內存時,被釋放的內存從堆中被剔除(堆被縮減)stack棧是用戶存放程序臨時創建的局部變量,也就是函數中定義的變量(但不包括 static 聲明的變量,static意味著在數據段中存放變量)。除此以外,在函數被調用時,其參數也會被壓入發起調用的進程棧中,並且待到調用結束後,函數的返回值也會被存放回棧中。由於棧的先進先出特點,所以棧特別方便用來保存/恢復調用現場。從這個意義上講,我們可以把堆棧看成一個寄存、交換臨時數據的內存區。上述幾種內存區域中數據段、BSS段、堆通常是被連續存儲在內存中,在位置上是連續的,而代碼段和棧往往會被獨立存放。堆和棧兩個區域在i386體系結構中棧向下擴展、堆向上擴展,相對而生。

你也可以再linux下用size 命令查看編譯後程序的各個內存區域大小:

內核空間

在 x86 32 位系統裡,Linux 內核地址空間是指虛擬地址從 0xC0000000 開始到 0xFFFFFFFF 為止的高端內存地址空間,總計 1G 的容量, 包括了內核鏡像、物理頁面表、驅動程序等運行在內核空間 。

直接映射區

直接映射區 Direct Memory Region:從內核空間起始地址開始,最大896M的內核空間地址區間,為直接內存映射區。

直接映射區的896MB的「線性地址」直接與「物理地址」的前896MB進行映射,也就是說線性地址和分配的物理地址都是連續的。內核地址空間的線性地址0xC0000001所對應的物理地址為0x00000001,它們之間相差一個偏移量PAGE_OFFSET = 0xC0000000該區域的線性地址和物理地址存在線性轉換關係「線性地址 = PAGE_OFFSET + 物理地址」也可以用 virt_to_phys()函數將內核虛擬空間中的線性地址轉化為物理地址。

高端內存線性地址空間

內核空間線性地址從 896M 到 1G 的區間,容量 128MB 的地址區間是高端內存線性地址空間,為什麼叫高端內存線性地址空間?下面給你解釋一下:

前面已經說過,內核空間的總大小 1GB,從內核空間起始地址開始的 896MB 的線性地址可以直接映射到物理地址大小為 896MB 的地址區間。退一萬步,即使內核空間的1GB線性地址都映射到物理地址,那也最多只能尋址 1GB 大小的物理內存地址範圍。

請問你現在你家的內存條多大?快醒醒都0202年了,一般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進程可以劃分為 5 個不同的內存區域,分別是:代碼段、數據段、BSS、堆、棧,內核管理這些區域的方式是,將這些內存區域抽象成vm_area_struct的內存管理對象。

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

鍊表用於需要遍歷全部節點的時候用,而紅黑樹適用於在地址空間中定位特定內存區域。內核為了內存區域上的各種不同操作都能獲得高性能,所以同時使用了這兩種數據結構。

用戶空間進程的地址管理模型:

內核空間動態分配內存數據結構

在內核空間章節我們提到過「動態內存映射區」,該區域由內核函數vmalloc來分配,特點是:線性空間連續,但是對應的物理地址空間不一定連續。

vmalloc 分配的線性地址所對應的物理頁可能處於低端內存,也可能處於高端內存。

vmalloc 分配的地址則限於vmalloc_start與vmalloc_end之間。每一塊vmalloc分配的內核虛擬內存都對應一個vm_struct結構體,不同的內核空間虛擬地址之間有4k大小的防越界空閒區間隔區。與用戶空間的虛擬地址特性一樣,這些虛擬地址與物理內存沒有簡單的映射關係,必須通過內核頁表才可轉換為物理地址或物理頁,它們有可能尚未被映射,當發生缺頁時才真正分配物理頁面。

總結一下

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

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

本文創作過程我也畫了大量的示例圖解,可以作為知識索引,個人感覺看圖還是比看文字更清晰明了。

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

相關焦點

  • 一張圖看懂Linux內核中Percpu變量的實現
    但你知道嗎,不僅是在程式語言中,在linux內核中,也有一個類似的機制,用來實現類似的目的,它叫做percpu變量。percpu變量,顧名思義,就是對於同一個變量,每個cpu都有自己的一份,它可以被用來存放一些cpu獨有的數據,比如cpu的id,cpu上正在運行的線程等等,因該機制可以非常方便的解決一些特定問題,所以在內核編程中被廣泛使用。
  • Java後端面試經驗:了解8大核心競爭點,讓你輕鬆通過面試!
    對此大家可以進一步了解HashMap(甚至ConcurrentHashMap)的底層實現。 3.ArrayList和LinkedList底層實現有什麼差別?它們各自適用於哪些場合?對此大家也可以了解下相關底層代碼。 4.volatile關鍵字有什麼作用?由此展開,大家可以了解下線程內存和堆內存的差別。
  • 面試官問「你為什麼離職」時,實際上是在問什麼?
    記得在上海面試的時候,由於簡歷寫得比較漂亮,年輕的面試官和老成持重的高層在悄聲說了幾句上海話之後,就發出了這樣的疑問: 「您之前表現堪稱完美,那麼還請問一下,是什麼原因讓您下定決心離開前公司嗎?」 那時候真的是很年輕,隨口說了句:「我想嘗試一下更大的平臺。」
  • 「你還有什麼要問我嗎?」面試官最後一問,21個最佳反問問題
    說起面試,可能每一位朋友都會多多少少有所了解,現在信息平臺如此發達,恐怕沒有人敢去「裸面」,一定會提前翻一翻「面經」。不過往往我們準備面試時,經常會忽略最後一個問題,「你還有什麼問題要問我嗎?」你還有什麼問題問我嗎?當你被問到這個「結束問題」時,其實並不是面試真的結束了,一方面面試官通過最後一個問題提示面試已經進入尾聲,另一方面想通過這個問題給求職者最後一個表達的機會。
  • 從串口驅動到Linux驅動模型,想轉Linux的必會!
    當Windows 10的升級提示從你計算機的右下角彈出時。你可以不假思索的點擊『馬上升級』嗎?我想大多數人對這個問題的答案是否定的。為什麼?因為大多數情況下。升級之後就會變得更卡。延遲更大。一些無用而龐大的軟體瘋狂的佔用你有限的計算機資源。而如果你選擇的是Linux。你幾乎可以任意的在計算機上安裝軟體。運行程序(如果你的內存不是太小。且硬碟交換分區足夠的話)。
  • 探討Linux作業系統虛擬內存和物理內存的關係
    探討Linux作業系統虛擬內存和物理內存的關係 TOMORROW 星辰 發表於 2020-12-10 16:12:20 為了高效、準確測試出該系統下,單個進程能夠申請到的最大虛存空間
  • 面試官沒說「你還有什麼要問我的?」是不是沒戲了?
    時光匆匆,今天是2021第一個工作日不知道大家假期玩得愉快嗎?回顧2020年第一篇與大家見面的推文來自粉絲提問也就是它《考研初試後開始找工作,應該注意些什麼?》4主動詢問期望薪資面試官在和你聊完你的過往經歷,職業目標,項目經驗等硬問題後,開始跟你聊薪資,或者圍繞薪資跟你展開了解。比如問你上家的薪資待遇,問你期望薪資,或者問你現在手上的offer滿不滿意等問題,至少可以證明在能力考查和個人履歷上,你是有很大機率候選的,而你對薪資的考量是面試官是否給你發放offer的關鍵。
  • 什麼Linux,Linux內核及Linux作業系統
    Linux內核並非作業系統而是實現了對計算機硬體的管理,是作業系統的基座,通常包括如下幾個方面:內存管理進程管理,其實就是對CPU的管理設備管理,例如滑鼠,鍵盤等文件管理從這張圖中我們可以看出作業系統與硬體及應用軟體間的關係。下面我們分別介紹一下各部分含義和作用。
  • 同學你會hello world嗎?給我講清楚點
    如上圖首先說下輸入過程,此圖做了一個濃縮,主要部件 鍵盤、主機(CPU、內存、磁碟)、顯示器代碼輸入過程看起來是蠻簡單的,打開一個編輯器或者IDE,即可開始代碼輸入剛開始學習推薦使用IDE,當然不是沒有IDE就不能寫代碼
  • 為什麼面試官喜歡問「你有什麼興趣愛好」?金牌HR帶你了解面試官
    「你有什麼興趣愛好」?很多人在面試的時候都被問過這個問題。大部分人都很疑惑為什麼面試工作的時候要被問興趣愛好?我的興趣愛好跟工作無關我能說嗎?我沒有什麼興趣愛好怎麼辦?今天跟大家聊聊為什麼面試官喜歡問「你有什麼興趣愛好」這個問題。
  • 您還有什麼想問的嗎?別回答沒有了,這樣問,做好面試的臨門一腳
    不知道大家發現沒有,面試快結束的時候,面試官們總愛問:「您還有什麼想問公司的嗎?」其實啊,這是一個印象加分題,通過求職者的回答,可以看出求職者是否真的很有邏輯分析能力、判斷能力,是否真的對公司很感興趣。
  • 面試官問「你接受加班嗎」,傻瓜才說不,高情商這樣說直接被錄用
    面試官問:」你接受加班嗎「,傻瓜才說」不「,高情商這樣說直接被錄用今年的疫情導致很多公司破產倒閉,也使部分人失業在家。如今疫情得到了緩解,畢業季也到了。大家都開始忙著投簡歷面試。然而在面試過程中大部分面試官都會問一個問題:「你接受加班嗎。」這個問題的回答的方式很有可能決定了你的去留。所以還是當心點吧。近期小王也一直都有在找工作,然而結果卻不盡人意,大部分的面試結果都不好,遭到拒絕。當我問到他原因時,他說是每個面試官都有問到他:「是否願意接受為公司加班。」他本人並不能接受,所以都拒絕了,說不能接受那麼高強度的加班內容。
  • 面試官:你還有什麼要問我的嗎?這樣回答讓你脫穎而出!
    當我們在平時參加面試的時候,在面試過程當中,面試官總會對我們說一句,你還有什麼問題要問呢?其實就是這麼一個簡單的問題,面試官就可以問出很多的東西,同時這個問題也暗藏很多的玄機。之所以聊這個問題,是因為我們公司HR前幾天面試了幾個新人,在面試的過程中,發現新人有一個共性問題,最後面試官問「還沒有問題問他」時,他們一致的回答是:「沒有了」或是「公司包一日三餐嗎?」這等無關痛癢的回答。而這樣的人第二天收到通知基本都是不合適,在面試的時候沉默,或者回答「沒有」的面試者。在面試時,通常處於下風。
  • 轉崗運營面試時,3個必答問題:是啥?咋做?問啥?
    莎莎憑藉著自己對面試流程的熟悉和溝通技巧,輕鬆的度過了第一輪hr面。但是到了第二輪業務leader面試時,第一問題就是問她「你認為什麼是運營?或者你是怎麼理解運營這個崗位呢?」莎莎突然有點懵,之前自己也面試過許多運營人員,運營到底是個啥呢?考慮了不到2分鐘,莎莎零散的聊了一些自己的想法。
  • 記一次優化Linux伺服器swap內存過高問題 - 51CTO.COM
    記一次優化Linux伺服器swap內存過高問題 今天收到zabbix告警,有點奇怪的是swap內存使用很高,但實際使用內存卻不多,下面一起來看看吧。
  • 大學生參加面試,面試官問:你能接受加班嗎?如何巧妙回答?
    HR:你能加班嗎?大學生進入社會後,一件重要的事情就是找到一份合適的工作,正式進入職場。大學生不能不去投遞簡歷,不能不參加面試。如果一個大學生的簡歷被僱主相中了,而這個大學生被邀請去面試,有個問題經常會被問到,你能接受加班嗎?當畢業生被問到這個問題時,許多學生不知所措,不知如何回答。
  • 內存時序很很重要嗎?3個知識點助你全面了解,選購內存不再糾結
    說實在的,不是我不想在有關內存的文章裡介紹內存時序,而是這個問題需要有一個專業的知識,很少有人會去注意這個問題的存在。平時我們在選購電腦內存條時,有很多人首先看中的是內存容量是多大?稍微有點硬體知識的可能還會問問內存頻率是多少?至於內存時序這個概念,估計很多人就不太了解了,也很少有人在選購內存時會問這個問題。
  • 面試官問,你撿到8萬失主說丟了10萬咋辦?女孩巧妙回答被錄用
    對於職場人來說,大家一定都經歷過面試這種事,肯定也經歷過面試官向你詢問一些問題,有時候面試官的問題還是比較正常的,但也不乏有些面試官在面試的時候會問求職者一些稀奇古怪的問題,那麼大家知道要怎麼回答嗎?1.撿到錢失主說少了怎麼辦?
  • 面試官:「你有什麼要問我的嗎?」,牢記這3個點,不懂別亂問
    我們在參加面試,面試到了最後一個環節的時候,面試官總會問你:你還有什麼要問我的嗎?你這個時候你們是怎麼說的呢?是有問題還是沒有問題呢?小明在參加面試的時候,曾經就在這個問題上栽過坑,當面試官問小明有沒有什麼問題要問的時候,小明回答說,基本上沒有什麼問題要問你了。
  • 天官賜福:風師驚豔登場,花憐細節好評,若邪安排得明明白白
    在半月關副本中,大家最期待的就是風師和黑水兩人的登場,漫畫中灰灰也畫得十分仙氣,兩人最開始只給大家留下背影和側面,但風師卻十分可愛,還做了一個眨眼的動作,與身後漫天黃沙的沙漠背景有些格格不入