共計 4294 個字符,預計需要花費 11 分鐘才能閱讀完成。
這篇文章主要介紹 Linux 物理內存外碎片化是什么意思,文中介紹的非常詳細,具有一定的參考價值,感興趣的小伙伴們一定要看完!
一、Linux 物理內存外碎片化概述
什么是 Linux 物理內存碎片化?Linux 物理內存碎片化包括兩種:
1. 物理內存內碎片:指分配給用戶的內存空間中未被使用的部分。
例如進程需要使用 3K bytes 物理內存,于是向系統申請了大小等于 3Kbytes 的內存,但是由于 Linux 內核伙伴系統算法最小顆粒是 4K bytes,所以分配的是 4Kbytes 內存,那么其中 1K bytes 未被使用的內存就是內存內碎片。
Linux 物理內存內碎片
2. 物理內存外碎片化:指系統中無法利用的小內存塊。
例如系統剩余內存為 16K bytes,但是這 16K bytes 內存是由 4 個 4K bytes 的頁面組成,即 16K 內存物理頁幀號 #1 不連續。在系統剩余 16K bytes 內存的情況下,系統卻無法成功分配大于 4K 的連續物理內存,該情況就是內存外碎片導致,本文中闡述的就是物理內存外碎片化。
注:#1 物理頁幀號:Linux 物理內存是通過頁面進行管理,并對每個頁面進行編號,稱為頁幀號,如果是連續的兩個物理頁面,其頁幀號是連續的。
Linux 物理內存外碎片
二、Linux 物理內存管理框架
闡述物理內存外碎片化的來龍去脈前,先得明白 Linux 是如何管理物理內存的?Linux 內核采用的是 buddy system allocation,即著名的伙伴系統分配器。
1. 設計思路
伙伴系統分配器的核心思路:將系統的空閑頁面分為 11 個塊鏈表,每個塊鏈表分別管理著 1,2,4,8,16,32,64,128,256,512 和 1024 個物理頁幀號連續的頁面。每個頁面大小為 4K bytes,buddy 管理的塊大小范圍從 4K bytes 到 4M bytes,以 2 的倍數遞增。
Linux 物理內存管理框架圖
2. 管理邏輯
Linux 對物理頁面管理的框架如上圖,由于本文闡述的是物理內存外碎片,所以關于伙伴系統本文只做簡單分析,不涉及具體的細節并不闡述關于 per cpu pageset 等內容,如果讀者有興趣,可以參考內核源碼。
Linux 將物理內存分為不同的 node 和 zone 來管理:
node:為了支持 NUMA 結構,即 CPU 對不同內存簇的訪問速度不同,Linux 設計了 node 結構,將物理內存分為多個內存節點管理; 對于 UMA 結構,只有一個 node 節點。
zone:為兼容不同的平臺的硬件限制,例如 80×86 的體系結構的硬件總線訪問等問題,Linux 將 node 節點下的內存分為多個 zone; 目前在 ARM 平臺,多個 zone 管理已非必要。
zone 管理單元下的內存通過 free_area 數組將內存分成 11 個塊鏈表進行管理:
free_area 數組總共有 11 個索引,每個索引管理著不同大小的塊鏈表。
free_area[0]管理的內存單位為 2^0 頁面,即 4K byte 內存;
free_area[1]管理的內存單位為 2^1 的物理頁幀號連續頁面,即 8K bytes 內存;
以此類推;
free_area 管理的內存還細分為各種類型,例如不可移動頁面和可移動頁面等,每種類型的頁面類型對應一個 free_list 鏈表,該鏈表就鏈接著頁面結構體。
當分配頁面時,伙伴系統拿頁面的步驟如下:(不考慮內存慢速路徑)
根據分配頁面類型,找到對應的內存節點 node 和內存管理單元 zone;
根據分配頁面大小,找到的對應大小的 free_area 結構體;
根據分配頁面類型,找到對應的 free_list 鏈表,分配頁面;
當向伙伴系統釋放頁面時,buddy 釋放頁面的步驟如下:
根據分配頁面類型,找到對應的內存節點 node 和內存管理單元 zone;
判斷是否有物理頁幀號相連的空閑內存塊,可以跟被釋放的內存塊合并成更大的塊內存,合并的條件:
物理幀必須都是連續的;
相同的類型和相同的大小;
合并后塊內存的第一個頁面的物理地址滿足”2* 塊大小 *4K”的倍數。
根據釋放頁面的大小或者合并的大小,找到的對應大小的 free_area 結構體;
根據釋放頁面的類型,找到對應的 free_list 鏈表,釋放頁面;
三、Linux 針對物理內存外碎片化的措施
從“二、Linux 物理內存管理架構”,可以發現伙伴系統內存管理框架是可以有效改善物理內存外碎片的,因為伙伴系統有如下兩個管理邏輯,可以減少了外碎片化的產生:
小塊內存在小塊鏈表分配,減少大塊鏈表被污染的概率;
內存釋放時會嘗試整合成大塊內存的邏輯,有助于大塊內存的合成;
除此之外,內核還支持以下措施改善物理內存外碎片化(只列舉主要的機制):
1.memory compaction
(1)內存規整原理
Linux 物理頁面規整機制,類似于磁盤整理,主要是應用了內核的頁面遷移機制,是一種將可移動頁面進行遷移后騰出連續物理內存的方法。
假設存在一個非常小的內存域如下:
藍色表示空閑的頁面,白色表示已經被分配的頁面,可以看到如上內存域的空閑頁面 (藍色) 非常零散,無法分配大于兩頁的連續物理內存。
下面演示一下內存規整的簡化工作原理,內核會運行兩個獨立的掃描動作:第一個掃描從內存域的底部開始,一邊掃描一邊將已分配的可移動 (MOVABLE) 頁面記錄到一個列表中:
另外第二掃描是從內存域的頂部開始,掃描可以作為頁面遷移目標的空閑頁面位置,然后也記錄到一個列表里面:
等兩個掃描在域中間相遇,意味著掃描結束,然后將左邊掃描得到的已分配的頁面遷移到右邊空閑的頁面中,左邊就形成了一段連續的物理內存,完成頁面規整。
(2)使用方法
如果想打開內存規整,內核需要打開相關的配置(默認為 y)
打開如上配置后,內存規整的觸發是自動的,觸發內存規整的途徑如下:當進程嘗試分配高階內存無法滿足并且完成 direct_reclaim#1(暫不分析 costly_order 情況)后,系統會根據內存剩余判斷是否觸發內存規整;
注:#1direct_reclaim:進程分配內存時發現內存不足從而啟動直接回收內存操作,這種模式下分配和回收是同步的關系,也就是說分配內存的進程會因為等待內存回收而被阻塞。
內核也提供了接口給用戶觸發規整動作,接口如下:
/proc/sys/vm/compact_memory
只要往這個節點寫值即可觸發對系統所有 node 管理的內存做內存規整。
2.kcompactd
(1)kcompact 設計原理
kcompactd 是一個內核規整的后臺進程,它跟 memory compaction 的區別在于:
memory compaction 的觸發途徑是內存分配進入 direct_reclaim(暫不分析 costly_order 情況)后系統會根據內存剩余判斷是否觸發內存規整,或者用戶手動觸發;
kcompactd 在喚醒 kswapd 或者 kswapd 進入休眠時,主動觸發內存規整。
kcompactd 的觸發路徑如下:主要有如下兩個途徑:
喚醒 kswapd 之前觸發規整,觸發的條件是:本次分配不支持 direct_reclaim,node 內存節點是平衡的,并且 kswapd 失敗的次數大于 MAX_RECLAIM_RETRIES(默認 16)。
kswapd 即將進入睡眠時:
(2)使用方法
如果想打開內存規整,內核需要打開相關的配置(默認為 y)
3. 其他優化的思路
內核經過不斷的優化,那為何 Linux 為何還有物理內存外碎片化呢? 那是因為物理內存外碎片化雖然是可以不斷優化的,但卻無法得到根除。目前的內核,我覺得導致物理外碎片化還有以下兩個主要原因:
不可移動頁面污染了內存環境,導致頁面規整失敗;
隨著系統不斷申請和釋放的頁面,導致伙伴系統分配的物理內存頁幀號越發隨機,從而導致內存被隔斷的概率越高,碎片化的程度越高,在 3.2 闡述。
針對以上兩個原因,以下的優化措施可能達到一定的優化效果:
(1)減少 UNMOVABLE 頁面污染內存環境
限制不可以移動頁面偷頁行為
Linux 內存分配中支持 fallback 機制,又叫偷頁機制。該機制是為了規避同個 zone 管理單位頁面類型剩余不平衡的問題,例如同個 zone,A 頁面類型空閑內存較多,B 頁面類型空閑內存卻非常緊缺,如果沒有偷頁機制,分配 B 頁面類型就會進入內存分配慢速路徑。有了偷頁機制,在同個 zone 管理單位,如果 UNMOVABLE 類型無空閑頁面,但是 MOVABLE 類型頁面還有空閑頁面,偷頁機制支持在 list_head[UNMOVABLE]分配不到頁面的情況下,向 list_head[MOVABLE]分配頁面。
以下數組明確了各種頁面類型可偷的頁面類型,例如第一行表示 UNMOVABLE 頁面可以偷 RECLAIMABLE 和 MOVABLE 類型的頁面,其他類似。
如果不可移動頁面頻繁的偷頁會導致不可移動頁面很快污染了內存環境,特別污染了可移動頁面的內存,對內存規整成功率的影響比較大。基于以上情況,可以在偷頁的機制上加上分配大小限制的判斷,不可移動頁面只有大塊內存分配才允許偷頁,以此減少不可移動頁面對內存環境的污染。
不可移動類型頁面偷頁后主動償還
該方法主要是不可移動頁面偷頁后的一種補償方法。如果發生不可移動頁面偷頁后,我們將該頁面記錄到一個列表,等后續不可移動頁面類型存在空閑頁面時,將所偷的頁面遷移回不可移動頁面中,從而降低不可移動頁面的污染。
(2)降低分配頁幀號的隨機性
假設有一塊小內存域如下,以下兩種內存分配方式哪種會導致嚴重的內存碎片化?
頁面從頭部開始分配,直到尾部;
頁面隨機從任何位置分配。
明顯是第二種內存分配方式的對內存外碎片化更不友好,而這點也是伙伴系統目前沒有解決的問題。伙伴系統雖然將內存規劃成各種大小的內存塊,以讓小內存分配在小塊鏈表分配,盡量不污染大塊內存鏈表,但是卻沒辦法保證小塊內存具體是在物理內存的哪個頁幀范圍分配。隨著系統的運行越久,小塊內存的分配的物理頁幀號越發隨機,那么其導致碎片化的概率就會越高。
預留法
根據這種情況,可以通過預留的方式進行相應的優化。
預留一定的內存專門用于小塊內存分配,經過這個優化措施后,可以有效降低小塊內存分配的物理頁幀號的隨機性,從而降低小塊內存污染內存環境的概率。
預留一定的內存專門用于大塊內存分配,經過該優化措施后,預留的內存被小塊內存污染的概率就會降低,可以提升預留內存分配大塊內存的成功率。
另外關于降低伙伴系統分配頁幀號隨機性,還是存在很多優化的措施,后續根據需要會專門開展一篇闡述該部分優化的文章,如果讀者有興趣,到時可以查閱。
以上是“Linux 物理內存外碎片化是什么意思”這篇文章的所有內容,感謝各位的閱讀!希望分享的內容對大家有幫助,更多相關知識,歡迎關注丸趣 TV 行業資訊頻道!