linux oom_score_adj

本文介绍了Linux系统中OOM(Out of Memory)杀手的工作原理及其关键参数oom_score_adj的作用。通过示例代码演示了内存不足时OOM杀手如何选择并终止进程,并展示了oom_score_adj设置对进程的影响。

文章系转载,便于整理和归纳

作者:欧阳_z
链接: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,范围是 -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 后果比较严重。

<think>我们正在处理用户关于使用ADB修改oom_score_adj的方法的问题。根据提供的引用,我们可以总结如下关键点: 1. oom_score_adjLinux内核中用于调整进程在内存紧张时被杀死优先级的机制。值范围在-1000到1000之间,值越低表示进程优先级越高,越不容易被杀死[^1][^4]。 2. 在Android系统中,我们可以通过修改进程的oom_score_adj值来调整其优先级。 3. 引用[5]给出了一个例子,展示了不同进程的oom_adj值(注意:这里提到的是oom_adj,但在较新的内核中,通常使用oom_score_adj)。 注意:在较新的Linux内核中(Android采用的内核),通常使用`oom_score_adj`(范围-1000到1000)替代旧的`oom_adj`(范围-17到15)。但是,在/proc文件系统中,我们仍然可以看到两个文件:`/proc/<pid>/oom_adj`和`/proc/<pid>/oom_score_adj`。在较新的系统中,修改`oom_adj`会映射到`oom_score_adj`上,但建议直接修改`oom_score_adj`。 用户问题:使用ADB修改oom_score_adj的方法。 步骤: 1. 获取要修改的进程的PID(进程ID)。 2. 通过ADB shell以root权限写入新的值到`/proc/<pid>/oom_score_adj`。 但是,需要注意: - 写入`oom_score_adj`需要root权限。 - 修改是临时的,进程重启后将恢复。 具体步骤: 1. 使用ADB连接到设备(确保设备已开启USB调试)。 ```bash adb shell ``` 2. 在ADB shell中获取需要修改的进程的PID。可以使用`ps`命令或`pgrep`命令。例如,查找微信的进程: ```bash ps -A | grep tencent ``` 或者 ```bash pgrep -f com.tencent.mm ``` 3. 切换到root用户(需要设备已root): ```bash su ``` 4. 使用`echo`命令写入新的值到对应进程的`oom_score_adj`文件。例如,将PID为12345的进程的oom_score_adj设置为-1000(最高优先级): ```bash echo "-1000" > /proc/12345/oom_score_adj ``` 或者,使用`printf`(以避免权限问题): ```bash printf "%s" "-1000" > /proc/12345/oom_score_adj ``` 注意:写入的值必须在-1000到1000之间。 另外,引用[3]提到了在Android的Java层可以通过`ProcessList.setOomAdj`来调整,但这需要修改系统框架(即需要系统级权限,通常只有系统应用或具有特定权限的应用才能调用),且一般不是通过ADB命令直接调用的。 因此,对于普通用户,如果设备已经root,可以通过ADB和上述步骤修改。 如果设备没有root,可能无法直接修改。但一些设备上,如果应用具有足够的权限(比如系统应用),可以通过ADB shell在没有root的情况下修改自己的进程(但一般不允许修改其他进程)。 另外,还有一种方式是通过`adb shell`使用`settings`命令,但这个命令通常用于修改系统设置,并不用于修改进程的oom_score_adj。 因此,我们主要提供root后的修改方法。 总结ADB修改步骤: 1. 连接设备:`adb shell` 2. 获取进程PID:`ps -A | grep <package_name>` 或 `pgrep -f <package_name>` 3. 切换到root:`su`(需要确认) 4. 修改oom_score_adj:`echo "<value>" > /proc/<pid>/oom_score_adj` 例如,将微信主进程的oom_score_adj设置为-1000(最高优先级): ```bash adb shell su pid=$(pgrep -f com.tencent.mm | head -1) # 获取第一个匹配的PID echo "-1000" > /proc/$pid/oom_score_adj ``` 注意:使用`pgrep`可能需要busybox支持,或者使用`ps`结合`grep`和`awk`。 如果设备不支持`pgrep`,可以使用: ```bash pid=$(ps -A | grep com.tencent.mm | awk '{print $2}' | head -1) ``` 最后,由于修改是临时的,每次进程重启后都需要重新设置。因此,可以编写脚本在每次启动时设置,或者通过其他方式持久化(但需要系统支持)。 另外,引用[5]中提到了一个例子:将应用的oom_adj值设置为0(对应于oom_score_adj的0?),但实际上oom_adjoom_score_adj的换算关系并不是线性的。在旧系统中,oom_adj的取值范围是-17到15,然后内核会将其转换为-1000到1000。在新系统中,建议直接使用oom_score_adj。 因此,我们直接修改oom_score_adj。 相关问题: 1. 在Android中调整进程优先级除了修改oom_score_adj还有哪些方法? 2. 如何让修改的oom_score_adj值在应用重启后仍然有效? 3. 在非root设备上如何调整进程的oom_adj? </think> ### 使用ADB修改`oom_score_adj`的方法 通过ADB修改进程的`oom_score_adj`需 **Root权限**,且修改只在进程存活期间有效。以下是详细步骤: #### 步骤 1:获取目标进程PID ```bash adb shell "ps -A | grep <进程名或包名>" # 示例:获取微信进程PID adb shell "ps -A | grep tencent" ``` 输出示例: ``` u0_a295 12420 ... com.tencent.mm:push ``` 记录目标进程的PID(如`12420`)。 #### 步骤 2:进入ADB Shell并提权 ```bash adb shell su # 获取Root权限(需设备已Root) ``` #### 步骤 3:修改`oom_score_adj`值 ```bash echo <目标值> > /proc/<PID>/oom_score_adj # 示例:将PID 12420的进程优先级设为最高(-1000) echo "-1000" > /proc/12420/oom_score_adj ``` **参数说明**: - **值范围**:`-1000`(最高优先级)到`1000`(最低优先级)[^1] - 系统进程通常为`0`,前台应用为`0~1`,后台服务可设为`5~9`[^5] #### 步骤 4:验证修改结果 ```bash cat /proc/<PID>/oom_score_adj # 示例:确认PID 12420的值 cat /proc/12420/oom_score_adj ``` 应输出设定的值(如`-1000`)。 --- ### ⚠ 注意事项 1. **临时性**:进程重启后恢复默认值,需脚本监控或Hook注入实现持久化。 2. **权限要求**: - 修改系统进程需`SELinux`权限调整[^4] - 非Root设备可通过`android:persistent`标志尝试(需系统签名) 3. **风险提示**: - 过度提升优先级可能导致系统OOM机制失衡 - 前台进程滥用(如设为`0`)可能被系统检测为异常[^5] --- ### 💡 替代方案(无需Root) 在应用代码中声明优先级(需系统权限): ```java // 系统级应用可使用 import android.os.Process; Process.setThreadPriority(Process.THREAD_PRIORITY_FOREGROUND); // 对应adj≈0[^3] ```
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值