1肆捕、在 linux 系統(tǒng)下,內(nèi)存不足會觸發(fā) OOM killer 去殺進(jìn)程
下面模擬一下誓军,幾秒之后顯示被Killed
了:
$ cat oom.c
#include <stdlib.h>
#include <stdio.h>
#define BYTES (8 * 1024 * 1024)
int main(void)
{
printf("hello OOM \n");
while(1)
{
char *p = malloc(BYTES);
if (p == NULL)
{
return -1;
}
}
return 0;
}
$ gcc oom.c
$ ./a.out
hello OOM
Killed
$
用 dmesg
命令可以看到相關(guān) log:
a.out invoked oom-killer: gfp_mask=0x26084c0, order=0, oom_score_adj=0
Out of memory: Kill process 97843 (a.out) score 835 or sacrifice child
2巾腕、oom_score_adj
上面打印了oom_score_adj=0
以及score 835
,OOM killer 給進(jìn)程打分闪湾,把 oom_score
最大的進(jìn)程先殺死冲甘。
打分主要有兩部分組成:
一是系統(tǒng)根據(jù)該進(jìn)程的內(nèi)存占用情況打分,進(jìn)程的內(nèi)存開銷是變化的响谓,所以該值也會動態(tài)變化损合。
二是用戶可以設(shè)置的 oom_score_adj
,范圍是 -1000
到 1000
娘纷,定義在:
https://elixir.bootlin.com/linux/v5.0/source/include/uapi/linux/oom.h#L9
/*
* /proc/<pid>/oom_score_adj set to OOM_SCORE_ADJ_MIN disables oom killing for
* pid.
*/
#define OOM_SCORE_ADJ_MIN (-1000)
#define OOM_SCORE_ADJ_MAX 1000
如果用戶將該進(jìn)程的 oom_score_adj 設(shè)定成 -1000
嫁审,表示禁止
OOM killer 殺死該進(jìn)程(代碼在 https://elixir.bootlin.com/linux/v5.0/source/mm/oom_kill.c#L222 )。比如 sshd
等非常重要的服務(wù)可以配置為 -1000
赖晶。
如果設(shè)置為負(fù)數(shù)律适,表示分?jǐn)?shù)會打一定的折扣,
如果設(shè)置為正數(shù)遏插,分?jǐn)?shù)會增加捂贿,可以優(yōu)先殺死該進(jìn)程,
如果設(shè)置為0
胳嘲,表示用戶不調(diào)整分?jǐn)?shù)厂僧,0
是默認(rèn)值。
3了牛、測試設(shè)置 oom_score_adj
對 oom_score
的影響
#include <stdlib.h>
#include <stdio.h>
#define BYTES (8 * 1024 * 1024)
#define N (10240)
int main(void)
{
printf("hello OOM \n");
int i;
for (i = 0; i < N; i++)
{
char *p = malloc(BYTES);
if (p == NULL)
{
return -1;
}
}
printf("while... \n");
while(1);
return 0;
}
下面是初始的分?jǐn)?shù):
$ cat /proc/$(pidof a.out)/oom_score_adj
0
$ cat /proc/$(pidof a.out)/oom_score
62
下面修改 oom_score_adj
颜屠,oom_score
也隨之發(fā)生了變化:
$ sudo sh -c "echo -50 > /proc/$(pidof a.out)/oom_score_adj"
$ cat /proc/$(pidof a.out)/oom_score_adj
-50
$ cat /proc/$(pidof a.out)/oom_score
12
$ sudo sh -c "echo -60 > /proc/$(pidof a.out)/oom_score_adj"
$ cat /proc/$(pidof a.out)/oom_score_adj
-60
$ cat /proc/$(pidof a.out)/oom_score
2
$ sudo sh -c "echo -500 > /proc/$(pidof a.out)/oom_score_adj"
$ cat /proc/$(pidof a.out)/oom_score_adj
-500
$ cat /proc/$(pidof a.out)/oom_score
0
4辰妙、測試設(shè)置 oom_score_adj
設(shè)置為-1000
對系統(tǒng)的影響
如果把一個(gè)無限申請內(nèi)存的進(jìn)程設(shè)置為-1000
,會發(fā)生什么呢:
$ sudo sh -c "echo -1000 > /proc/$(pidof a.out)/oom_score_adj"
$ dmesg | grep "Out of memory"
Out of memory: Kill process 1000 (mysqld) score 67 or sacrifice child
Out of memory: Kill process 891 (vmhgfs-fuse) score 1 or sacrifice child
Out of memory: Kill process 321 (systemd-journal) score 1 or sacrifice child
Out of memory: Kill process 1052 ((sd-pam)) score 1 or sacrifice child
Out of memory: Kill process 1072 (bash) score 0 or sacrifice child
因?yàn)?bash
掛了甫窟,所以 a.out
也掛了密浑。
如果 ./a.out &
在后臺運(yùn)行,就可以看到用更多進(jìn)程的 score 是 0 仍然掛掉了粗井,比如 sshd尔破、dhclient、systemd-logind浇衬、systemd-timesyn懒构、dbus-daemon 等,所以設(shè)置錯(cuò)誤的 oom_score_adj
后果比較嚴(yán)重径玖。