[转帖]oom_score_adj

oom,score,adj · 浏览次数 : 0

小编点评

**内存不足的 OOM killer 处理过程** **步骤 1:内存申请** * 进程首先使用 `malloc()` 函数申请 8MB 的内存。 * 如果申请失败,进程将返回 `NULL`。 **步骤 2:循环申请内存** * 进程使用 `while (1)` 循环申请内存,直到 `malloc()` 返回 `NULL`。 * 每一次申请 8MB 的内存。 **步骤 3:打印 OOM 信息** * 进程打印一行消息,表示 OOM killer 被触发。 * 进程将一直循环地打印 `hello OOM`。 **步骤 4:设置 OOM 评分** * 进程设置不同的 OOM 评分值,例如 `-1000`、`-50`、`0` 或 `1000`。 * 这些值定义了进程在 OOM 评分方面的优先级。 **步骤 5:设置 OOM 评分的限制** * 用户可以通过 `oom_score_adj` 设置 OOM 评分的限制。 * 如果 `oom_score_adj` 设置为 `-1000`,表示 OOM killer 将不杀死该进程。 **测试设置** * 使用 `oom_score_adj` 设置为 `-1000`,以便测试 OOM killer 不杀进程的行为。 * 启动多个进程,每个进程都设置不同的 OOM 评分。 * 使用 `dmesg` 命令查看 OOM 评分。 **结果** 当 `oom_score_adj` 设置为 `-1000` 时,多个进程将无法获得内存,OOM killer 将给它们打分,把它们杀死。

正文

https://www.jianshu.com/p/bbaeff371019

 

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,范围是 -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

如果用户将该进程的 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_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;
}

下面是初始的分数:

$ 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 后果比较严重。

与[转帖]oom_score_adj相似的内容:

[转帖]oom_score_adj

https://www.jianshu.com/p/bbaeff371019 1、在 linux 系统下,内存不足会触发 OOM killer 去杀进程下面模拟一下,几秒之后显示被Killed了: $ cat oom.c #include #include

[转帖]oom-killer错误排查过程

https://www.cnblogs.com/hphua/p/16395893.html 1、遇到的问题:应用在hi3536上跑一段不固定的时间,随之就会出现重启的现象;打印如下; app-run invoked oom-killer: gfp_mask=0x1042d0, order=3, oo

[转帖]JVM中OOM常见几种类型

https://www.cnblogs.com/shemlo/p/11665917.html Java中的OOM java.lang.StackOverflowError java.lang.OutMemoryError:Java heap space java.lang.OutMemoryErro

[转帖]高手总结的9种 OOM 常见原因及解决方案

https://zhuanlan.zhihu.com/p/79355050 当 JVM 内存严重不足时,就会抛出 java.lang.OutOfMemoryError 错误。本文总结了常见的 OOM 原因及其解决方法,如下图所示。如有遗漏或错误,欢迎补充指正。 1、Java heap space 当

[转帖]一次 Java 进程 OOM 的排查分析(glibc 篇)

https://juejin.cn/post/6854573220733911048 遇到了一个 glibc 导致的内存回收问题,查找原因和实验的的过程是比较有意思的,主要会涉及到下面这些: Linux 中典型的大量 64M 内存区域问题 glibc 的内存分配器 ptmalloc2 的底层原理 如

[转帖]一次 Java 进程 OOM 的排查分析(glibc 篇)

https://juejin.cn/post/6854573220733911048 遇到了一个 glibc 导致的内存回收问题,查找原因和实验的的过程是比较有意思的,主要会涉及到下面这些: Linux 中典型的大量 64M 内存区域问题 glibc 的内存分配器 ptmalloc2 的底层原理 如

[转帖]【JVM】Java内存区域与OOM

引入 Java与C++之间有一堵由内存动态分配和垃圾收集技术所围成的“高墙”,墙外面的人想进去,墙里面的人却想出来。 Java虚拟机运行时数据区 如图所示 1.程序计数器(线程私有) 作用 记录当前线程所执行到的字节码的行号。字节码解释器工作的时候就是通过改变这个计数器的值来选取下一条需要执行的字节

[转帖][问题已处理]-kubernetes中2次不同的oom处理

https://dandelioncloud.cn/article/details/1598699030236577793 起因: 同事反馈 服务挂了,kuboard上查看是服务挂掉了,liveness port 异常,通过查看pod状态,发现服务被重启了。 1 pod里的java进程因为k8s主机

[转帖]【JVM】Java内存区域与OOM

引入 Java与C++之间有一堵由内存动态分配和垃圾收集技术所围成的“高墙”,墙外面的人想进去,墙里面的人却想出来。 Java虚拟机运行时数据区 如图所示 1.程序计数器(线程私有) 作用 记录当前线程所执行到的字节码的行号。字节码解释器工作的时候就是通过改变这个计数器的值来选取下一条需要执行的字节

[转帖]总结:记一次K8S容器OOM案例

一、背景 最近遇到个现象,hubble-api-open组件过段时间会内容占满,从而被K8S强制重启。 让我困惑的是,已经设置了-XX:MaxRAMPercentage=75.0,我觉得留有了一定的空间,不应该会占满,所以想深究下原因。 -XX:MaxRAMPercentage是设置JVM的最大堆内