轉載自:http://blog.chinaunix.net/uid-29242873-id-3942763.html
Linux 內核有個機制叫OOM killer(Out-Of-Memory killer),該機制會監控那些佔用內存過大,尤其是瞬間很快消耗大量內存的進程,爲了防止內存耗盡而內核會把該進程殺掉。典型的情況是:某天一臺機器突然ssh遠程登錄不了,但能ping通,說明不是網絡的故障,原因是sshd進程被OOM killer殺掉了(多次遇到這樣的假死狀況)。重啓機器後查看系統日誌/var/log/messages會發現Out of Memory: Kill process 1865(sshd)類似的錯誤信息。
防止重要的系統進程觸發(OOM)機制而被殺死:可以設置參數/proc/PID/oom_adj爲-17,可臨時關閉linux內核的OOM機制。內核會通過特定的算法給每個進程計算一個分數來決定殺哪個進程,每個進程的oom分數可以/proc/PID/oom_score中找到。我們運維過程中保護的一般是sshd和一些管理agent。
保護某個進程不被內核殺掉可以這樣操作:
點擊(此處)摺疊或打開
echo -17 > /proc/$PID/oom_adj
如何防止sshd被殺,可以這樣操作:
點擊(此處)摺疊或打開
pgrep -f "/usr/sbin/sshd" | while read PID;do echo -17 > /proc/$PID/oom_adj;done
點擊(此處)摺疊或打開
#/etc/cron.d/oom_disable
*/1**** root pgrep -f "/usr/sbin/sshd" | while read PID;do echo -17 > /proc/$PID/oom_adj;done
點擊(此處)摺疊或打開
echo -17 > /proc/$(pidof sshd)/oom_adj
至於爲什麼用-17而不用其他數值(默認值爲0),這個是由linux內核定義的,查看內核源碼可知:
以linux-3.3.6版本的kernel源碼爲例,路徑爲linux-3.6.6/include/linux/oom.h,閱讀內核源碼可知oom_adj的可調值爲15到-16,其中15最大-16最小,-17爲禁止使用OOM。oom_score爲2的n次方計算出來的,其中n就是進程的oom_adj值,所以oom_score的分數越高就越會被內核優先殺掉。
點擊(此處)摺疊或打開
vm.panic_on_oom = 1 //1表示關閉,默認爲0表示開啓OOM
# sysctl -p
爲了驗證OOM機制的效果,我們不妨做個測試。
首先看看我係統現有內存大小,沒錯96G多,物理上還要比查看的值大一些。
再看看目前進程最大的有哪些,top查看,我目前只跑了兩個java程序的進程,分別4.6G,再往後redis進程吃了21m,iscsi服務佔了32m,gdm佔了25m,其它的進程都是幾M而已。
現在我自己用C寫一個叫bigmem程序,我指定該程序分配內存85G
點擊(此處)摺疊或打開
-
#include <stdio.h>
-
#include <stdlib.h>
-
#include <string.h>
-
-
#define PAGE_SZ (1<<12)
-
-
int main() {
-
int i;
-
int gb = 85; //以GB爲單位分配內存大小
-
-
for (i = 0; i < ((unsigned
long)gb<<30)/PAGE_SZ ; ++i) {
-
void *m = malloc(PAGE_SZ);
-
if (!m)
-
break;
-
memset(m, 0, 1);
-
}
-
printf("allocated %lu MB\n", ((unsigned
long)i*PAGE_SZ)>>20);
-
getchar();
-
return 0;
- }
繼續觀察,當bigmem穩定保持在85G一會後,內核會自動將其進程kill掉,增長的過程中沒有被殺,如果不希望被殺可以執行
點擊(此處)摺疊或打開
pgrep -f "bigmem" | while read PID; do echo -17 > /proc/$PID/oom_adj;done
執行以上命令前後,明顯會對比出效果,就可以體會到內核OOM機制的實際作用了。
如果你覺得寫C代碼麻煩,我告訴大家另外一個最簡單的測試觸發OOM的方法,可以把某個進程的oom_adj設置到15(最大值),最容易觸發。然後執行以下命令:
點擊(此處)摺疊或打開
- echo f > /proc/sysrq-trigger // 'f' - Will call oom_kill to kill a memory hog process.
點擊(此處)摺疊或打開
- ps -ef | grep mysqld | grep -v grep
注意:
1.Kernel-2.6.26之前版本的oomkiller算法不夠精確,RHEL 6.x版本的2.6.32可以解決這個問題。
2.子進程會繼承父進程的oom_adj。
3.OOM不適合於解決內存泄漏(Memory leak)的問題。
4.有時free查看還有充足的內存,但還是會觸發OOM,是因爲該進程可能佔用了特殊的內存地址空間。