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);
....