Linux記憶體管理系統引數配置之OOM(記憶體耗盡)

2021-10-08 16:05:37 字數 4515 閱讀 6540

一、前言

本文是描述linux virtual memory執行引數的第二篇,主要是講oom相關的引數的。為了理解oom引數,第二章簡單的描述什麼是oom。如果這個名詞對你毫無壓力,你可以直接進入第三章,這一章是描述具體的引數的,除了描述具體的引數,我們引用了一些具體的核心**,本文的**來自4.0核心,如果有興趣,可以結合**閱讀,為了縮減篇幅,文章中的**都是刪減版本的。按照慣例,最後一章是參考文獻,本文的參考文獻都是來自linux核心的documentation目錄,該目錄下有大量的文件可以參考,每一篇都值得細細品味。

二、什麼是oom

oom就是out of memory的縮寫,雖然linux kernel有很多的記憶體管理技巧(從cache中**、swap out等)來滿足各種應用空間的vm記憶體需求,但是,當你的系統配置不合理,讓一匹小馬拉大車的時候,linux kernel會執行非常緩慢並且在某個時間點分配page frame的時候遇到記憶體耗盡、無法分配的狀況。應對這種狀況首先應該是系統管理員,他需要首先給系統增加記憶體,不過對於kernel而言,當面對oom的時候,咱們也不能慌亂,要根據oom引數來進行相應的處理。

三、oom引數

1、panic_on_oom

當kernel遇到oom的時候,可以有兩種選擇:

(1)產生kernel panic(就是死給你看)。

(2)積極面對人生,選擇乙個或者幾個最「適合」的程序,啟動oom killer,乾掉那些選中的程序,釋放記憶體,讓系統勇敢的活下去。

panic_on_oom這個引數就是控制遇到oom的時候,系統如何反應的。當該引數等於0的時候,表示選擇積極面對人生,啟動oom killer。當該引數等於2的時候,表示無論是哪一種情況,都強制進入kernel panic。panic_on_oom等於其他值的時候,表示要區分具體的情況,對於某些情況可以panic,有些情況啟動oom killer。kernel的**中,enum oom_constraint 就是乙個進一步描述oom狀態的引數。系統遇到oom總是有各種各樣的情況的,kernel中定義如下:

對於uma而言, oom_constraint永遠都是constraint_none,表示系統並沒有什麼約束就出現了oom,不要想太多了,就是記憶體不足了。在numa的情況下,有可能附加了其他的約束導致了系統遇到oom狀態,實際上,系統中還有充足的記憶體。這些約束包括:

(1)constraint_cpuset。cpusets是kernel中的一種機制,通過該機制可以把一組cpu和memory node資源分配給特定的一組程序。這時候,如果出現oom,僅僅說明該程序能分配memory的那個node出現狀況了,整個系統有很多的memory node,其他的node可能有充足的memory資源。

(2)constraint_memory_policy。memory policy是numa系統中如何控制分配各個memory node資源的策略模組。使用者空間程式(numa-aware的程式)可以通過memory policy的api,針對整個系統、針對乙個特定的程序,針對乙個特定程序的特定的vma來制定策略。產生了oom也有可能是因為附加了memory policy的約束導致的,在這種情況下,如果導致整個系統panic似乎有點不太合適吧。

(3)constraint_memcg。memcg就是memory control group,cgroup這東西太複雜,這裡不適合多說,cgroup中的memory子系統就是控制系統memory資源分配的控制器,通俗的將就是把一組程序的記憶體使用限定在乙個範圍內。當這一組的記憶體使用超過上限就會oom,在這種情況下的oom就是constraint_memcg型別的oom。

ok,了解基礎知識後,我們來看看核心**。核心中sysctl_panic_on_oom變數是和/proc/sys/vm/panic_on_oom對應的,主要的判斷邏輯如下:

當系統選擇了啟動oom killer,試圖殺死某些程序的時候,又會遇到這樣的問題:乾掉哪個,哪乙個才是「合適」的哪那個程序?系統可以有下面的選擇:

(1)誰觸發了oom就乾掉誰

(2)誰最「壞」就乾掉誰

oom_kill_allocating_task這個引數就是控制這個選擇路徑的,當該引數等於0的時候選擇(2),否則選擇(1)。具體的**可以在參考__out_of_memory函式,具體如下:

當然也不能說殺就殺,還是要考慮是否使用者空間程序(不能殺核心執行緒)、是否unkillable task(例如init程序就不能殺),使用者空間是否通過設定引數(oom_score_adj)阻止kill該task。如果萬事俱備,那麼就呼叫oom_kill_process乾掉當前程序。

3、oom_dump_tasks

當系統的記憶體出現oom狀況,無論是panic還是啟動oom killer,做為系統管理員,你都是想保留下線索,找到oom的root cause,例如dump系統中所有的使用者空間程序關於記憶體方面的一些資訊,包括:程序標識資訊、該程序使用的total virtual memory資訊、該程序實際使用物理記憶體(我們又稱之為rss,resident set size,不僅僅是自己程式使用的物理記憶體,也包含共享庫占用的記憶體),該程序的頁表資訊等等。拿到這些資訊後,有助於了解現象(出現oom)之後的真相。

當設定為0的時候,上一段描述的各種程序們的記憶體資訊都不會列印出來。在大型的系統中,有幾千個程序,逐一列印每乙個task的記憶體資訊有可能會導致效能問題(要知道當時已經是oom了)。當設定為非0值的時候,在下面三種情況會呼叫dump_tasks來列印系統中所有task的記憶體狀況:

(1)由於oom導致kernel panic

(2)沒有找到適合的「bad」process

(3)找適合的並將其乾掉的時候

4、oom_adj、oom_score_adj和oom_score

準確的說這幾個引數都是和具體程序相關的,因此它們位於/proc/***/目錄下(***是程序id)。假設我們選擇在出現oom狀況的時候殺死程序,那麼乙個很自然的問題就浮現出來:到底乾掉哪乙個呢?核心的演算法倒是非常簡單,那就是打分(oom_score,注意,該引數是read only的),找到分數最高的就ok了。那麼怎麼來算分數呢?可以參考核心中的oom_badness函式:

(1)對某乙個task進行打分(oom_score)主要有兩部分組成,一部分是系統打分,主要是根據該task的記憶體使用情況。另外一部分是使用者打分,也就是oom_score_adj了,該task的實際得分需要綜合考慮兩方面的打分。如果使用者將該task的 oom_score_adj設定成oom_score_adj_min(-1000)的話,那麼實際上就是禁止了oom killer殺死該程序。

(2)這裡返回了0也就是告知oom killer,該程序是「good process」,不要乾掉它。後面我們可以看到,實際計算分數的時候最低分是1分。

(3)前面說過了,系統打分就是看物理記憶體消耗量,主要是三部分,rss部分,swap file或者swap device上占用的記憶體情況以及頁表占用的記憶體情況。

(4)root程序有3%的記憶體使用特權,因此這裡要減去那些記憶體使用量。

(5)使用者可以調整oom_score,具體如何操作呢?oom_score_adj的取值範圍是-1000~1000,0表示使用者不調整oom_score,負值表示要在實際打分值上減去乙個折扣,正值表示要懲罰該task,也就是增加該程序的oom_score。在實際操作中,需要根據本次記憶體分配時候可分配記憶體來計算(如果沒有記憶體分配約束,那麼就是系統中的所有可用記憶體,如果系統支援cpuset,那麼這裡的可分配記憶體就是該cpuset的實際額度值)。oom_badness函式有乙個傳入引數totalpages,該引數就是當時的可分配的記憶體上限值。實際的分數值(points)要根據oom_score_adj進行調整,例如如果oom_score_adj設定-500,那麼表示實際分數要打五折(基數是totalpages),也就是說該任務實際使用的記憶體要減去可分配的記憶體上限值的一半。

了解了oom_score_adj和oom_score之後,應該是塵埃落定了,oom_adj是乙個舊的介面引數,其功能類似oom_score_adj,為了相容,目前仍然保留這個引數,當操作這個引數的時候,kernel實際上是會換算成oom_score_adj,有興趣的同學可以自行了解,這裡不再細述了。

四、參考文獻

1、documentation/vm/numa_memory_policy.txt

2、documentation/sysctl/vm.txt

3、documentation/cgroup/cpusets.txt

4、documentation/cgroup/memory.txt

Linux系統記憶體管理簡介

linux記憶體管理之物理空間 linux核心中有個全域性變數mem map,指向乙個page資料結構的陣列,每個page資料結構代表著乙個物理頁面,整個資料就代表著系統中的全部物理頁面。頁表項的高20位對於軟體和mmu硬體有著不同的意義。對於軟體,這是乙個物理頁面的序號,將這個序號用作下標就可以從...

Linux系統的記憶體管理

dos時代 同一時間只能有乙個程序在執行 也有一些特殊演算法可以支援多程序 windows9x 多個程序裝入記憶體存在問題 1 記憶體不夠用 2 互相打擾 1.解決記憶體撐爆問題 lru演算法 leetcode 146題 分頁 記憶體不夠用 記憶體中分成固定大小的頁框 4k 把程式 硬碟上 分成4k...

Linux系統的記憶體管理

drop caches 的值可以是 0 3 之間的數字,代表不同的含義 0 不釋放 系統預設值 1 釋放頁快取 2 釋放dentries和inode 3 釋放所有快取 修改 echo 1 proc sys vm drop caches 代表釋放頁快取 free命令相對於top,提供了更簡潔的檢視系統...