linux OOM-killer机制(杀掉进程,释放内存)
Linux下面有個(gè)特性叫OOM killer(Out Of Memory killer),這個(gè)東西會(huì)在系統(tǒng)內(nèi)存耗盡的情況下跳出來,選擇性的干掉一些進(jìn)程以求釋放一些內(nèi)存。相信廣大從事Linux服務(wù)端編程的農(nóng)民工兄弟們或多或少遇到過(人在江湖漂,哪有不挨刀啊)。典型的情況是:某天機(jī)器突然登不上了,能ping通,但是ssh死活連不了。原因是sshd進(jìn)程被OOM killer干掉了(淚流滿面)。重啟機(jī)器后查看系統(tǒng)日志會(huì)發(fā)現(xiàn)血淋淋的Out of Memory: Killed process ×××、Out of Memory: Killed process 〇〇〇。一篇狼藉,慘不忍睹。
前段時(shí)間我就被OOM killer虐過一次。情況是這樣的。一個(gè)簡單的分布式系統(tǒng),A,B,C等對(duì)稱的節(jié)點(diǎn)分擔(dān)處理X節(jié)點(diǎn)吐出的數(shù)據(jù),然后將結(jié)果塞到Y(jié)節(jié)點(diǎn)去。結(jié)果負(fù)荷一大,ABC處理不過來,數(shù)據(jù)堆積在內(nèi)存中,內(nèi)存耗光,逼得OOM killer出來收拾局面,sshd被干掉,更杯具的是,重啟后發(fā)現(xiàn),syslogd也被干掉了,而且是在sshd前面被干掉。想查日志也只能查到一部分。血淋淋的。這也引出了分布式系統(tǒng)設(shè)計(jì)中的問題:想上面那種設(shè)計(jì),要防止ABC中某個(gè)節(jié)點(diǎn)突然掛掉,然后導(dǎo)致其他節(jié)點(diǎn)負(fù)荷突然增加緊跟著也掛掉(連鎖掛掉)。
回歸正題,Linux下面的OOM killer到底是什么樣一個(gè)機(jī)制呢,它在什么時(shí)候會(huì)跳出來,又會(huì)選擇那些進(jìn)程下手呢。
什么時(shí)候跳出來
先看第一個(gè)問題,它什么時(shí)候會(huì)跳出來。是不是malloc返回NULL的時(shí)候跳出來呢?不是的,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返回非空指針,并不一定意味著指向的內(nèi)存就是可用的,Linux下允許程序申請(qǐng)比系統(tǒng)可用內(nèi)存更多的內(nèi)存,這個(gè)特性叫Overcommit。這樣做是出于優(yōu)化系統(tǒng)考慮,因?yàn)椴皇撬械某绦蛏暾?qǐng)了內(nèi)存就立刻使用的,當(dāng)你使用的時(shí)候說不定系統(tǒng)已經(jīng)回收了一些資源了。不幸的是,當(dāng)你用到這個(gè)Overcommit給你的內(nèi)存的時(shí)候,系統(tǒng)還沒有資源的話,OOM killer就跳出來了。
Linux下有3種Overcommit的策略(參考內(nèi)核文檔:vm/overcommit-accounting),可以在/proc/sys/vm/overcommit_memory配置。取0,1和2三個(gè)值,默認(rèn)是0。
0:啟發(fā)式策略,比較嚴(yán)重的Overcommit將不能得逞,比如你突然申請(qǐng)了128TB的內(nèi)存。而輕微的Overcommit將被允許。另外,root能Overcommit的值比普通用戶要稍微多些。
1:永遠(yuǎn)允許Overcommit,這種策略適合那些不能承受內(nèi)存分配失敗的應(yīng)用,比如某些科學(xué)計(jì)算應(yīng)用。
2:永遠(yuǎn)禁止Overcommit,在這個(gè)情況下,系統(tǒng)所能分配的內(nèi)存不會(huì)超過swap+RAM*系數(shù)(/proc/sys/vm/overcmmit_ratio,默認(rèn)50%,你可以調(diào)整),如果這么多資源已經(jīng)用光,那么后面任何嘗試申請(qǐng)內(nèi)存的行為都會(huì)返回錯(cuò)誤,這通常意味著此時(shí)沒法運(yùn)行任何新程序。
補(bǔ)充(待考證):在這篇文章:Memory overcommit in Linux中,作者提到,實(shí)際上啟發(fā)策略只有在啟用了SMACK或者SELinux模塊時(shí)才會(huì)起作用,其他情況下等于永遠(yuǎn)允許策略。
跳出來之后選擇進(jìn)程的策略
好了,只要存在Overcommit,就可能會(huì)有OOM killer跳出來。那么OOM killer跳出來之后選目標(biāo)的策略又是什么呢?我們期望的是:沒用的且耗內(nèi)存多的程序被槍。
Linux下這個(gè)選擇策略也一直在不斷的演化。作為用戶,我們可以通過設(shè)置一些值來影響OOM killer做出決策。Linux下每個(gè)進(jìn)程都有個(gè)OOM權(quán)重,在/proc/<pid>/oom_adj里面,取值是-17到+15,取值越高,越容易被干掉。
最終OOM killer是通過/proc/<pid>/oom_score這個(gè)值來決定哪個(gè)進(jìn)程被干掉的。這個(gè)值是系統(tǒng)綜合進(jìn)程的內(nèi)存消耗量、CPU時(shí)間(utime + stime)、存活時(shí)間(uptime - start time)和oom_adj計(jì)算出的,消耗內(nèi)存越多分越高,存活時(shí)間越長分越低。總之,總的策略是:損失最少的工作,釋放最大的內(nèi)存同時(shí)不傷及無辜的用了很大內(nèi)存的進(jìn)程,并且殺掉的進(jìn)程數(shù)盡量少。
另外,Linux在計(jì)算進(jìn)程的內(nèi)存消耗的時(shí)候,會(huì)將子進(jìn)程所耗內(nèi)存的一半同時(shí)算到父進(jìn)程中。這樣,那些子進(jìn)程比較多的進(jìn)程就要小心了。
當(dāng)然還有其他的策略,大家可以參考文章:Taming the OOM killer和When Linux Runs Out of Memory。
總結(jié)
以上是生活随笔為你收集整理的linux OOM-killer机制(杀掉进程,释放内存)的全部內(nèi)容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: mongodb 对内存的严重占用以及解决
- 下一篇: mysql主从同步-问题梳理