1. 程式人生 > >[Linux] OOM-killer機制(殺掉程序,釋放記憶體)

[Linux] OOM-killer機制(殺掉程序,釋放記憶體)

Linux下面有個特性叫OOM killer(Out Of Memory killer),這個東西會在系統記憶體耗盡的情況下跳出來,選擇性的幹掉一些程序以求釋放一些記憶體。相信廣大從事Linux服務端程式設計的農民工兄弟們或多或少遇到過(人在江湖漂,哪有不挨刀啊)。典型的情況是:某天機器突然登不上了,能ping通,但是ssh死活連不了。原因是sshd程序被OOM killer幹掉了(淚流滿面)。重啟機器後檢視系統日誌會發現血淋淋的Out of Memory: Killed process ×××、Out of Memory: Killed process 〇〇〇。一篇狼藉,慘不忍睹。

前段時間我就被OOM killer虐過一次。情況是這樣的。一個簡單的分散式系統,A,B,C等對稱的節點分擔處理X節點吐出的資料,然後將結果塞到Y節點去。結果負荷一大,ABC處理不過來,資料堆積在記憶體中,記憶體耗光,逼得OOM killer出來收拾局面,sshd被幹掉,更杯具的是,重啟後發現,syslogd也被幹掉了,而且是在sshd前面被幹掉。想查日誌也只能查到一部分。血淋淋的。這也引出了分散式系統設計中的問題:想上面那種設計,要防止ABC中某個節點突然掛掉,然後導致其他節點負荷突然增加緊跟著也掛掉(連鎖掛掉)。

迴歸正題,Linux下面的OOM killer到底是什麼樣一個機制呢,它在什麼時候會跳出來,又會選擇那些程序下手呢。

什麼時候跳出來

先看第一個問題,它什麼時候會跳出來。是不是malloc返回NULL的時候跳出來呢?不是的,malloc的manpage裡有下面一段話:

By default, Linux follows an  optimistic  memory  allocation  strategy.  This  means  that  when malloc() returns non-NULL there is no guarantee  that the memory really is available.  This is a  really  bad  bug.   In  case  it  turns  out that the system is out of memory, one or more processes  will be killed by the infamous OOM killer.   In  case  Linux  is  employed  under  circumstances where it would be less desirable to suddenly  lose some randomly picked processes, and moreover the kernel version   is  sufficiently  recent,  one can switch off this overcommitting  behavior using a command like:

# echo 2 > /proc/sys/vm/overcommit_memory

上面一段話告訴我們,Linux中malloc返回非空指標,並不一定意味著指向的記憶體就是可用的,Linux下允許程式申請比系統可用記憶體更多的記憶體,這個特性叫Overcommit。這樣做是出於優化系統考慮,因為不是所有的程式申請了記憶體就立刻使用的,當你使用的時候說不定系統已經回收了一些資源了。不幸的是,當你用到這個Overcommit給你的記憶體的時候,系統還沒有資源的話,OOM killer就跳出來了。

Linux下有3種Overcommit的策略(參考核心文件:vm/overcommit-accounting),可以在/proc/sys/vm/overcommit_memory配置。取0,1和2三個值,預設是0。

0:啟發式策略,比較嚴重的Overcommit將不能得逞,比如你突然申請了128TB的記憶體。而輕微的Overcommit將被允許。另外,root能Overcommit的值比普通使用者要稍微多些。

1:永遠允許Overcommit,這種策略適合那些不能承受記憶體分配失敗的應用,比如某些科學計算應用。

2:永遠禁止Overcommit,在這個情況下,系統所能分配的記憶體不會超過swap+RAM*係數(/proc/sys/vm/overcmmit_ratio,預設50%,你可以調整),如果這麼多資源已經用光,那麼後面任何嘗試申請記憶體的行為都會返回錯誤,這通常意味著此時沒法執行任何新程式。

補充(待考證):在這篇文章:Memory overcommit in Linux中,作者提到,實際上啟發策略只有在啟用了SMACK或者SELinux模組時才會起作用,其他情況下等於永遠允許策略。

跳出來之後選擇程序的策略

好了,只要存在Overcommit,就可能會有OOM killer跳出來。那麼OOM killer跳出來之後選目標的策略又是什麼呢?我們期望的是:沒用的且耗記憶體多的程式被槍。

Linux下這個選擇策略也一直在不斷的演化。作為使用者,我們可以通過設定一些值來影響OOM killer做出決策。Linux下每個程序都有個OOM權重,在/proc/<pid>/oom_adj裡面,取值是-17到+15,取值越高,越容易被幹掉。

最終OOM killer是通過/proc/<pid>/oom_score這個值來決定哪個程序被幹掉的。這個值是系統綜合程序的記憶體消耗量、CPU時間(utime + stime)、存活時間(uptime - start time)和oom_adj計算出的,消耗記憶體越多分越高,存活時間越長分越低。總之,總的策略是:損失最少的工作,釋放最大的記憶體同時不傷及無辜的用了很大記憶體的程序,並且殺掉的程序數儘量少。

另外,Linux在計算程序的記憶體消耗的時候,會將子程序所耗記憶體的一半同時算到父程序中。這樣,那些子程序比較多的程序就要小心了。

原文地址:https://blog.csdn.net/hunanchenxingyu/article/details/26271293?utm_source=copy