欢迎您访问程序员文章站本站旨在为大家提供分享程序员计算机编程知识!
您现在的位置是: 首页

lmkd mem_pressure计算与作用

程序员文章站 2022-04-20 20:02:19
...

Android Q以后,google推荐使用lmkd,lmkd其中一种工作模式是根据内存压力去kill进程.

https://source.android.google.cn/devices/tech/perf/lmkd文档中:

mem_pressure = 内存使用量/RAM_and_swap 使用量(以百分比的形式表示)

具体到代码中:

   if ((mem_usage = get_memory_usage(&mem_usage_file_data)) < 0) {
        goto do_kill;
    }
    if ((memsw_usage = get_memory_usage(&memsw_usage_file_data)) < 0) {
        goto do_kill;
    }

    // Calculate percent for swappinness.
    mem_pressure = (mem_usage * 100) / memsw_usage;
    //添加log,能够查看内存压力等级
    ALOGI("mem_usage = %lld KB memsw_usage = %lld KB  mem_pressure  =  %lld " ,mem_usage/1024 , memsw_usage /1024,mem_pressure);
    if (enable_pressure_upgrade && level != VMPRESS_LEVEL_CRITICAL) {
        // We are swapping too much.
        if (mem_pressure < upgrade_pressure) {
            level = upgrade_level(level);
            if (debug_process_killing) {
                ALOGI("Event upgraded to %s", level_name[level]);
            }
        }
    }

可以看到

mem_pressure = (mem_usage * 100) / memsw_usage;
mem_usage = get_memory_usage(&mem_usage_file_data)
memsw_usage = get_memory_usage(&memsw_usage_file_data)

#define MEMCG_MEMORY_USAGE "/dev/memcg/memory.usage_in_bytes"
#define MEMCG_MEMORYSW_USAGE "/dev/memcg/memory.memsw.usage_in_bytes"

从代码中看到查看到是去读取两个节点.这两个节点存储的数据的含义就是:

1.内存使用量

2.RAM_and_swap 使用量

我们具体去cat一下并且计算开机后的内存压力.

E:\02_Project>adb shell cat /dev/memcg/memory.usage_in_bytes
568688640

E:\02_Project>adb shell cat /dev/memcg/memory.memsw.usage_in_bytes
762757120

mem_pressure = 568688640*100/762757120 = 74.5

即现在样机的内存压力为74.5.

如果使用apk,那么zram会增加.mem_pressure的数值会变小.

mem_pressure的数值与以下系统属性有关.

    ro.lmk.low=1001\
    ro.lmk.medium=800\
    ro.lmk.critical=0\
    ro.lmk.upgrade_pressure=40\
    ro.lmk.downgrade_pressure=60\

从代码可以看到:

if (mem_pressure < upgrade_pressure) {
            level = upgrade_level(level);
            if (debug_process_killing) {
                ALOGI("Event upgraded to %s", level_name[level]);
            }
        }

 if (mem_pressure > downgrade_pressure) {
            if (debug_process_killing) {
                ALOGI("Ignore %s memory pressure", level_name[level]);
            }
            return;
        } else if (level == VMPRESS_LEVEL_CRITICAL && mem_pressure > upgrade_pressure) {
            if (debug_process_killing) {
                ALOGI("Downgrade critical memory pressure");
            }
            // Downgrade event, since enough memory available.
            level = downgrade_level(level);
        }

如果
mem_pressure<40 ,内存压力等级升级.
如果
mem_pressure > 60,内存压力等级降级

压力等级为:

enum vmpressure_level {
    VMPRESS_LEVEL_LOW = 0,
    VMPRESS_LEVEL_MEDIUM,
    VMPRESS_LEVEL_CRITICAL,
    VMPRESS_LEVEL_COUNT
};

其中:

level与oomadj有对应关系.

 /* By default disable low level vmpressure events */
    level_oomadj[VMPRESS_LEVEL_LOW] =
        property_get_int32("ro.lmk.low", OOM_SCORE_ADJ_MAX + 1);
    level_oomadj[VMPRESS_LEVEL_MEDIUM] =
        property_get_int32("ro.lmk.medium", 900);
    level_oomadj[VMPRESS_LEVEL_CRITICAL] =
        property_get_int32("ro.lmk.critical", 0);

根据我们的配置:

ro.lmk.low = 1001

ro.lmk.medium = 800
ro.lmk.critical = 0

所以

level_oomadj[VMPRESS_LEVEL_LOW] =1001
level_oomadj[VMPRESS_LEVEL_MEDIUM] =800
level_oomadj[VMPRESS_LEVEL_CRITICAL] =0

下面是kill进程

if (low_ram_device) {
        /* For Go devices kill only one task */
        if (find_and_kill_process(level_oomadj[level]) == 0) {
            if (debug_process_killing) {
                ALOGI("Nothing to kill");
            }
        } else {
            meminfo_log(&mi);
        }
    }


level_oomadj[level]=1001/800/0

这里前面计算的level的等级会转换为oom_adj=1001/800/0

 接下来会到:

 

retry:
    for (i = OOM_SCORE_ADJ_MAX; i >= min_score_adj; i--) {
        struct proc *procp;

        while (true) {
            procp = kill_heaviest_task ?
                proc_get_heaviest(i) : proc_adj_lru(i);

            if (!procp)
                break;

            killed_size = kill_one_process(procp, min_score_adj);
            if (killed_size >= 0) {
#ifdef LMKD_LOG_STATS
                if (enable_stats_log && !lmk_state_change_start) {
                    lmk_state_change_start = true;
                    stats_write_lmk_state_changed(log_ctx, LMK_STATE_CHANGED,
                                                  LMK_STATE_CHANGE_START);
                }
#endif
                break;
            }
        }
        if (killed_size) {
            break;
        }
    }

 

killed_size = kill_one_process(procp, min_score_adj);
kill_one_process中最终会调用:

 r = kill(pid, SIGKILL);杀掉指定pid进程.