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

内存白名单策略

程序员文章站 2022-05-19 10:10:19
...

转载请注明链接

由于Android的内存管理机制,在开发过程中常见的两种内存回收杀死App情况有以下两种:
内存紧张时LowMemoryKiller杀死。
空闲进程被AMS杀死。
定制手机ROM时,开发人员可能并不想让自己的预装应用被以上两种机制杀死,可以采用添加内存白名单的方式防止系统对预装应用进行回收处理。

1. 重要数组:

// These are the various interesting memory levels that we will give to
// the OOM killer.  Note that the OOM killer only supports 6 slots, so we
// can't give it a different value for every possible kind of process.

在/frameworks/base/services/java/com/android/server/am/ProcessList.java文件中定义了如下三个数组:

  • Adj数组

    OOM killer仅支持6个slots,分别为:

   //前台进程
   static final int FOREGROUND_APP_ADJ = 0;
   //可见进程
   static final int VISIBLE_APP_ADJ = 1;
   //可感知进程,如酷狗player的进程
   static final int PERCEPTIBLE_APP_ADJ = 2;
   //备份进程
   static final int BACKUP_APP_ADJ = 3;
   //空进程
   static final int CACHED_APP_MIN_ADJ = 9;
   static final int CACHED_APP_MAX_ADJ = 15;
   private final int[] mOomAdj = new int[] {
            FOREGROUND_APP_ADJ, VISIBLE_APP_ADJ, PERCEPTIBLE_APP_ADJ,
           BACKUP_APP_ADJ, CACHED_APP_MIN_ADJ, CACHED_APP_MAX_ADJ
   };
  • 内存阈值数组

    各个进程level被杀死的内存阈值,android4.4已按照不同的设备类型给出了两类内存阈值数组.

    private final long[] mOomMinFreeLow = new long[] {
            8192, 12288, 16384,
            24576, 28672, 32768
    };
    private final long[] mOomMinFreeHigh = new long[] {
            49152, 61440, 73728,
            86016, 98304, 122880
   };

开发人员可根据自身设备的内存及App运行情况对上述两个数组自行调整。比如某个重要的App占用内存较多,需要常驻的后台服务,那么可以修改BACKUP_APP_ADJ——>SERVICE_ADJ,并调整对应的内存阈值。

2. LowMemoryKiller:

具体实现/drivers/staging/android/lowmemorykiller.c:
处理函数 lowmem_shrinker:

static int lowmem_shrink(struct shrinker *s, struct shrink_control *sc)
{
     ……  
    //循环遍历内存阀值数组,计算最小触发内存killer的adj值
    for (i = 0; i < array_size; i++) {      
        minfree = lowmem_minfree[i];
        if (other_free < minfree && other_file < minfree) {
            min_score_adj = lowmem_adj[i];
            break;
        }
    }
    selected_oom_score_adj = min_score_adj;
    ……
    // 循环遍历所有process,找出大于min_score_adj的process,筛选出oom_score_adj最大且占用内存最大的process,kill之
    for_each_process(tsk) {
    ……
        p = find_lock_task_mm(tsk);
        oom_score_adj = p->signal->oom_score_adj;
        // 该process不满足上面找到的需要杀死process的最小adj,继续遍历
        if (oom_score_adj < min_score_adj) {
            task_unlock(p);
            continue;
        }
        // 此处是白名单设定,重点关注
        // 先判断是不是要回收VISIBLE_APP_ADJ级别之上的process,如果是,则不再判断白名单,因为此时内存已经非常紧张了。
        if (min_score_adj >= BACKUP_APP_ADJ){
            // 如果需要kill的process在VISIBLE_APP_ADJ级别之下,则判断该进程是否在白名单,如果是,不予kill
            if (is_in_whitelist(p->comm))
            { 
                task_unlock(p);
                continue;
            }
        }

        tasksize = get_mm_rss(mm);
        task_unlock(p);
        if (tasksize <= 0)
            continue;
        if (selected) {
            // 该process的oom_score_adj小于上个循环筛选出的adj,继续遍历
            if (oom_score_adj < selected_oom_score_adj)
                continue;
            // 该process的内存占用小于上个循环筛选出的同adj的process,继续遍历
            if (oom_score_adj == selected_oom_score_adj &&
                tasksize <= selected_tasksize)
                continue;
        }
        selected = p;
        selected_tasksize = tasksize;
        selected_oom_score_adj = oom_score_adj;
    }
    //send SIGKILL杀死这个占用最大内存的process
    if (selected) {
        ……
        trace_lowmem_kill(selected,  other_file, minfree, min_score_adj, other_free);

        lowmem_deathpending_timeout = jiffies + HZ;
        send_sig(SIGKILL, selected, 0); 
        set_tsk_thread_flag(selected, TIF_MEMDIE);
        rem -= selected_tasksize;
    }
}

如下代码为白名单过滤代码:

// 先判断是不是要回收VISIBLE_APP_ADJ级别之上的process,如果是,则不再判断白名单,因为此时内存已经非常紧张了。
if (min_score_adj >= BACKUP_APP_ADJ){
    // 如果需要kill的process在VISIBLE_APP_ADJ级别之下,则判断该进程是否在白名单,如果是,不予kill
    if (is_in_whitelist(p->comm))
    { 
        task_unlock(p);
        continue;
    }
}
// 白名单whitelist.txt:
com.company.packagename……

3. 空闲进程AMS回收:

待续