oom_score_adj

1、在 linux 系統下,內存不足會觸發 OOM killer 去殺進程
下面模擬一下,幾秒之后顯示被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 命令可以看到相關 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 給進程打分,把 oom_score 最大的進程先殺死。
打分主要有兩部分組成:
一是系統根據該進程的內存占用情況打分,進程的內存開銷是變化的,所以該值也會動態變化。
二是用戶可以設置的 oom_score_adj,范圍是 -10001000,定義在:
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

如果用戶將該進程的 oom_score_adj 設定成 -1000,表示禁止OOM killer 殺死該進程(代碼在 https://elixir.bootlin.com/linux/v5.0/source/mm/oom_kill.c#L222 )。比如 sshd 等非常重要的服務可以配置為 -1000。
如果設置為負數,表示分數會打一定的折扣,
如果設置為正數,分數會增加,可以優先殺死該進程,
如果設置為0 ,表示用戶不調整分數,0 是默認值。

3、測試設置 oom_score_adjoom_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;
}

下面是初始的分數:

$ cat /proc/$(pidof a.out)/oom_score_adj
0
$ cat /proc/$(pidof a.out)/oom_score
62

下面修改 oom_score_adjoom_score 也隨之發生了變化:

$ 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、測試設置 oom_score_adj 設置為-1000 對系統的影響
如果把一個無限申請內存的進程設置為-1000,會發生什么呢:

$ 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

因為 bash 掛了,所以 a.out 也掛了。
如果 ./a.out & 在后臺運行,就可以看到用更多進程的 score 是 0 仍然掛掉了,比如 sshd、dhclient、systemd-logind、systemd-timesyn、dbus-daemon 等,所以設置錯誤的 oom_score_adj 后果比較嚴重。

?著作權歸作者所有,轉載或內容合作請聯系作者
平臺聲明:文章內容(如有圖片或視頻亦包括在內)由作者上傳并發布,文章內容僅代表作者本人觀點,簡書系信息發布平臺,僅提供信息存儲服務。