AndroidQ lmkd

kill触发条件


static void mp_event_common(int data, uint32_t events __unused) {
    .... 省略
    
    //meminfo_parse  解析 /proc/meminfo,完成mi初始化
    //zoneinfo_parse 解析 /proc/zoneinfo,完成zi初始化
    //详见 1.1
    if (meminfo_parse(&mi) < 0 || zoneinfo_parse(&zi) < 0) {
        ALOGE("Failed to get free memory!");
        return;
    }

    if (use_minfree_levels) {
        int i;
        //计算剩余内存 meminfo.memfree - (zoneinfo.high + zoneinfo.protected)
        other_free = mi.field.nr_free_pages - zi.field.totalreserve_pages;

        // 计算meminfo内存页 
        // (buffers + swap_cached + cached) > (unevictable + shmem + swap_cached)
        if (mi.field.nr_file_pages > (mi.field.shmem + mi.field.unevictable + mi.field.swap_cached)) {
            other_file = (mi.field.nr_file_pages - mi.field.shmem -
                          mi.field.unevictable - mi.field.swap_cached);
        } else {
            other_file = 0; //没有内存页
        }

        min_score_adj = OOM_SCORE_ADJ_MAX + 1;
        for (i = 0; i < lowmem_targets_size; i++) {
            // 详见1.2
            // lowmem_minfree 可以通过属性`sys.lmk.minfree_levels`查看 
            minfree = lowmem_minfree[i];
            if (other_free < minfree && other_file < minfree) {
                // 触发do_kill
                min_score_adj = lowmem_adj[i];
                break;
            }
        }

        if (min_score_adj == OOM_SCORE_ADJ_MAX + 1) {
            if (debug_process_killing) {
                ALOGI("Ignore %s memory pressure event "
                      "(free memory=%ldkB, cache=%ldkB, limit=%ldkB)",
                      level_name[level], other_free * page_k, other_file * page_k,
                      (long)lowmem_minfree[lowmem_targets_size - 1] * page_k);
            }
            return;
        }
        // 见1.3
        goto do_kill;
    }



}

1.1 meminfo_parse 和 zoneinfo_parse

可以看出struct meminfo分别对应/proc/meminfo的字段
nr_free_pages对应MemFree
nr_file_pages对应Buffers+cached+swap_cached

union meminfo {
    struct {
        int64_t nr_free_pages;  
        int64_t cached;
        int64_t swap_cached;
        int64_t buffers;
        int64_t shmem;
        int64_t unevictable;
        int64_t total_swap;
        int64_t free_swap;
        int64_t active_anon;
        int64_t inactive_anon;
        int64_t active_file;
        int64_t inactive_file;
        int64_t sreclaimable;
        int64_t sunreclaimable;
        int64_t kernel_stack;
        int64_t page_tables;
        int64_t ion_heap;
        int64_t ion_heap_pool;
        int64_t cma_free;
        /* fields below are calculated rather than read from the file */
        int64_t nr_file_pages;
    } field;
    int64_t arr[MI_FIELD_COUNT];
};


static const char* const meminfo_field_names[MI_FIELD_COUNT] = {
    "MemFree:",
    "Cached:",
    "SwapCached:",
    "Buffers:",
    "Shmem:",
    "Unevictable:",
    "SwapTotal:",
    "SwapFree:",
    "Active(anon):",
    "Inactive(anon):",
    "Active(file):",
    "Inactive(file):",
    "SReclaimable:",
    "SUnreclaim:",
    "KernelStack:",
    "PageTables:",
    "ION_heap:",
    "ION_heap_pool:",
    "CmaFree:",
};


static int meminfo_parse(union meminfo *mi) {
    static struct reread_data file_data = {
        .filename = MEMINFO_PATH, //   /proc/meminfo
        .fd = -1,
    };
    char buf[PAGE_SIZE];
    char *save_ptr;
    char *line;

    memset(mi, 0, sizeof(union meminfo));

    if (reread_file(&file_data, buf, sizeof(buf)) < 0) {
        return -1;
    }

    for (line = strtok_r(buf, "\n", &save_ptr); line;
         line = strtok_r(NULL, "\n", &save_ptr)) {
        if (!meminfo_parse_line(line, mi)) {
            ALOGE("%s parse error", file_data.filename);
            return -1;
        }
    }
    
    /*  
        /proc/meminfo
        Buffers:           27964 kB
        Cached:          5084224 kB
        SwapCached:            0 kB
    */
    mi->field.nr_file_pages = mi->field.cached + mi->field.swap_cached +
        mi->field.buffers;
    
    return 0;
}

可以看出totalreserve_pages就是high+ protection累加

//字段
static const char* const zoneinfo_field_names[ZI_FIELD_COUNT] = {
    "nr_free_pages",
    "nr_file_pages",
    "nr_shmem",
    "nr_unevictable",
    "workingset_refault",
    "high",
};


union zoneinfo {
    struct {
        int64_t nr_free_pages;
        int64_t nr_file_pages;
        int64_t nr_shmem;
        int64_t nr_unevictable;
        int64_t workingset_refault;
        int64_t high;
        /* fields below are calculated rather than read from the file */
        int64_t totalreserve_pages;
    } field;
    int64_t arr[ZI_FIELD_COUNT];
};


static int zoneinfo_parse(union zoneinfo *zi) {
    static struct reread_data file_data = {
        .filename = ZONEINFO_PATH, // /proc/zoneinfo
        .fd = -1,
    };
    char buf[PAGE_SIZE];
    char *save_ptr;
    char *line;

    memset(zi, 0, sizeof(union zoneinfo));

    if (reread_file(&file_data, buf, sizeof(buf)) < 0) {
        return -1;
    }

    for (line = strtok_r(buf, "\n", &save_ptr); line;
         line = strtok_r(NULL, "\n", &save_ptr)) {
        if (!zoneinfo_parse_line(line, zi)) {
            ALOGE("%s parse error", file_data.filename);
            return -1;
        }
    }
    /*  zoneinfo_parse_line 还有一段代码,这里就不贴了
        if (!strcmp(cp, "protection:")) {
            zi->field.totalreserve_pages +=
                zoneinfo_parse_protection(ap);
        }
        所以 totalreserve_pages = high + protection
     */
    zi->field.totalreserve_pages += zi->field.high;

    return 0;
}

1.2 lowmem_minfree的赋值

static void cmd_target(int ntargets, LMKD_CTRL_PACKET packet)
{
    ... //省略部分
    
    char minfree_str[PROPERTY_VALUE_MAX];
    char *pstr = minfree_str;
    char *pend = minfree_str + sizeof(minfree_str);

    // packet 是am 通过socket传递
    for (i = 0; i < ntargets; i++) {
        lmkd_pack_get_target(packet, i, &target);
        lowmem_minfree[i] = target.minfree;
        lowmem_adj[i] = target.oom_adj_score;
        // pstr指向minfree_str的地址
        pstr += snprintf(pstr, pend - pstr, "%d:%d,", target.minfree,
            target.oom_adj_score);
        if (pstr >= pend) {
            /* if no more space in the buffer then terminate the loop */
            pstr = pend;
            break;
        }
    }

    lowmem_targets_size = ntargets;

    /* Override the last extra comma */
    pstr[-1] = '\0';
    property_set("sys.lmk.minfree_levels", minfree_str);

}

1.3 do_kill

do_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);
        }
    } else {
        int pages_freed;
        static struct timespec last_report_tm;
        static unsigned long report_skip_count = 0;

        if (!use_minfree_levels) {
            /* Free up enough memory to downgrate the memory pressure to low level */
            // max_nr_free_pages 就是 mi->field.nr_free_pages的一份记录,有兴趣可以看函数 record_low_pressure_levels
            if (mi.field.nr_free_pages >= low_pressure_mem.max_nr_free_pages) {
                if (debug_process_killing) {
                    ALOGI("Ignoring pressure since more memory is "
                        "available (%" PRId64 ") than watermark (%" PRId64 ")",
                        mi.field.nr_free_pages, low_pressure_mem.max_nr_free_pages);
                }
                return;
            }
            min_score_adj = level_oomadj[level];
        }

        // 对/proc/pid/oom_score_adj大于min_score_adj的进程进行kill
        // 返回释放的内存页
        pages_freed = find_and_kill_process(min_score_adj);
        ....

上一篇:JWT令牌


下一篇:浅析布隆过滤器(Bloom Filter)的实现原理及应用