當(dāng)Linux內(nèi)存耗盡時(shí),該如何處理!

當(dāng)內(nèi)存不足時(shí)會(huì)發(fā)生什么,結(jié)果很簡單,linux的內(nèi)存用完了,無法申請(qǐng)緩沖區(qū),內(nèi)核會(huì)挑選進(jìn)程將其殺死,一般情況下,殺死正在申請(qǐng)內(nèi)存的程序。頻繁的進(jìn)行磁盤swap操作,經(jīng)常會(huì)出現(xiàn)這類問題,或是并發(fā)處理時(shí)啟動(dòng)的進(jìn)程數(shù)過多。

出現(xiàn)內(nèi)存耗盡的原因很簡單,你申請(qǐng)的內(nèi)存大小,超過了可用的虛擬內(nèi)存的大小,注意是虛擬內(nèi)存(內(nèi)存并不是唯一的,交換分區(qū)也可以提供內(nèi)存)

探究oom(out of memory)

首先運(yùn)行下面的程序,不斷申請(qǐng)大量內(nèi)存:

#include<stdio.h>#include<stdlib.h>#define MEGABYTE 1024*1024intmain(intargc,char*argv[]){void*myblock=NULL;intcount=0;while(1){myblock=(void*)malloc(MEGABYTE);if(!myblock)break;printf("Currently allocating %d MB\n",++count);}exit(0);}

上面的程序運(yùn)行一會(huì)就會(huì)出現(xiàn)oom,現(xiàn)在運(yùn)行另外一個(gè)程序,不斷申請(qǐng)內(nèi)存,并且將其填充1。

#include<stdio.h>#include<stdlib.h>#define MEGABYTE 1024*1024intmain(intargc,char*argv[]){void*myblock=NULL;intcount=0;while(1){myblock=(void*)malloc(MEGABYTE);if(!myblock)break;memset(myblock,1,MEGABYTE);printf("Currently allocating %d MB\n",++count);}exit(0);}

有發(fā)現(xiàn)不同嗎,事實(shí)上程序1可以比程序2申請(qǐng)更多的內(nèi)存。兩個(gè)程序退出的原因都是因?yàn)榭臻g不夠了,然而程序1的退出時(shí)因?yàn)閙alloc的失敗,而程序2的退出則是因?yàn)閮?nèi)核所謂的oom killer 將其殺死了。

程序2退出的時(shí)候:

Currently allocatinn 1589 MB

程序1退出的時(shí)候:

Currently allocating 274520 MB(64位系統(tǒng))

為什么程序1相較程序2可以多分配如此多的內(nèi)存,這是因?yàn)閘inux采用了延遲的頁面分配。也就是說內(nèi)存只有在真正用的時(shí)候才進(jìn)行分配,這種技術(shù)被稱為optimistic memory allocation。

查看/proc/pid/status文件就可以知道這個(gè)情況。(其中vmdata是所占用的虛擬內(nèi)存)

首先是程序1:

然后是程序2:

當(dāng)我們請(qǐng)求一個(gè)內(nèi)存區(qū)時(shí),c庫會(huì)判斷當(dāng)前預(yù)分配的內(nèi)存塊是否足夠大,如果不夠,程序會(huì)通過擴(kuò)展堆空間的方式來獲取內(nèi)存。

查看文件/proc/pid/maps可以看到堆里的內(nèi)存塊。

在內(nèi)存用盡的時(shí)候oom killer會(huì)依據(jù)策略挑選需要?dú)⑺赖倪M(jìn)程進(jìn)行kill操作,策略是可以配置的。每個(gè)進(jìn)程的oom_score是動(dòng)態(tài)變化的,越大越可能被殺死。

通過查看/proc/pid/oom_score 可以知曉該進(jìn)程的值。一般來說占用內(nèi)存越多的值越高,運(yùn)行時(shí)間越早的值越小。

同時(shí)在系統(tǒng)里面有些相對(duì)重要的進(jìn)程可能會(huì)得到較高的值,這個(gè)時(shí)候可以使用/proc/pid/oom_adj文件。把里面的數(shù)值設(shè)置為整數(shù),這個(gè)進(jìn)程就越有可能被殺掉,相反設(shè)置為負(fù)數(shù),就越有機(jī)會(huì)存活。當(dāng)這個(gè)值為-17,oom-killer就會(huì)完全忽略這個(gè)進(jìn)程。

當(dāng)然這種方式不容易實(shí)現(xiàn)和管理,有其他編寫代碼管理oom-killer的方法。

如果系統(tǒng)有日志的話,killer的日志會(huì)保存到

grep -i kill /var/log/messages*

依據(jù)這個(gè)日志,可以調(diào)整策略,保證重要進(jìn)程的正常運(yùn)行,例如數(shù)據(jù)庫和web服務(wù)。

oom-killer的代碼位于mm/oom_kill.c

其調(diào)用的順序是malloc -> _alloc_pages -> out_of_memory() -> select_bad_process() -> badness()

【文章福利】小生推薦自己的Linux后臺(tái)/內(nèi)核技術(shù)交流群【 318652197】整理了一些個(gè)人覺得比較好的學(xué)習(xí)書籍,視頻資料共享在群文件里面,有需要的自行添加哦?。?!前100名進(jìn)群領(lǐng)取,額外贈(zèng)送一份價(jià)值699的內(nèi)核資料包(含視頻、電子書、實(shí)戰(zhàn)項(xiàng)目及代碼)

資料免費(fèi)領(lǐng)

學(xué)習(xí)直通車

?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請(qǐng)聯(lián)系作者
【社區(qū)內(nèi)容提示】社區(qū)部分內(nèi)容疑似由AI輔助生成,瀏覽時(shí)請(qǐng)結(jié)合常識(shí)與多方信息審慎甄別。
平臺(tái)聲明:文章內(nèi)容(如有圖片或視頻亦包括在內(nèi))由作者上傳并發(fā)布,文章內(nèi)容僅代表作者本人觀點(diǎn),簡書系信息發(fā)布平臺(tái),僅提供信息存儲(chǔ)服務(wù)。

相關(guān)閱讀更多精彩內(nèi)容

友情鏈接更多精彩內(nèi)容