Lmk
oom_adj 和oom_score_adj
都是打分因子,表示被杀的得分情况, 得分越高,越容易被杀。
- oom_adj
取值范围是-17至15, 取值为-17 的进程永远不会被杀。 - oom_score_adj
取值-1000至1000,取值-1000 的进程不会被杀。 - oom_adj 和oom_score_adj 的关系
内核中使用oom_score_adj, 位于task.signal.oom_score_adj字段中。那么
oom_adj 有什么用呢?当写入oom_adj 时会被换算为oom_score_adj。
公式如下: oom_score_adj = oom_adj *1000/17.
其实就是直接线性映射。 - 设置oom_adj 后,一定会生效吗?
如果oom_adj 换算成的oom_score_adj 比当前的低,也就是降低被杀的可能性,那么需要权限,如果没权限,则返回error;权限检查通过才会生效。 - 有权限设置oom_adj 后,再获取oom_adj,为什么值和设置的不一样?
oom_adj = oom_score_adj * 17/1000; 和当时换算时是相反的操作,由于oom_adj 取值-17 到15, 不是17的整数倍,那么算下来肯定会少1.
linux oomkiller 和Android lowmemorykiller
linux 内核有oom killer机制,是内存管理模块在内存资源短缺时触发的内存释放操作,将一些oom_score_adj 比较高的进程杀了释放内存。
Android 中还引入了一个lowmemorykiller机制,原理也是通过类似的打分机制,和oomkiller的区别时,oomkiller是等系统内存紧张,实在没多少内存分配时才触发;而lowmemorykiller是 内存低于某个阈值就触发。
minfree 和adj
/sys/module/lowmemorykiller/parameters/minfree
18432, 23040, 27648, 32256, 55296, 80640
/sys/module/lowmemorykiller/parameters/adj
0, 100, 200, 300, 900, 906
表示内存低于80640 时,就杀死oom_score_adj 大于906的进程。
static int lowmem_shrink(struct shrinker *s, struct shrink_control *sc)
{
...
// 获取当前系统剩余内存,以page为单位
int other_free = global_page_state(NR_FREE_PAGES) - totalreserve_pages;
int other_file = global_page_state(NR_FILE_PAGES) -
global_page_state(NR_SHMEM);
for (i = 0; i < array_size; i++) {
if (other_free < lowmem_minfree[i] &&
other_file < lowmem_minfree[i]) {
min_score_adj = lowmem_adj[i];
break;
}
}
...
selected_oom_score_adj = min_score_adj;
rcu_read_lock();
// 遍历所有进程PCB
for_each_process(tsk) {
struct task_struct *p;
int oom_score_adj;
if (tsk->flags & PF_KTHREAD)
continue;
p = find_lock_task_mm(tsk);
...
oom_score_adj = p->signal->oom_score_adj;
if (oom_score_adj < min_score_adj) {
task_unlock(p);
continue;
}
tasksize = get_mm_rss(p->mm);
task_unlock(p);
if (tasksize <= 0)
continue;
if (selected) {
// 检查优先级是否更低
if (oom_score_adj < selected_oom_score_adj)
continue;
// 如果平级,查看是否占用更多内存
if (oom_score_adj == selected_oom_score_adj &&
tasksize <= selected_tasksize)
continue;
}
// 选中该进程
// 如果后续没有优先级更低或者占用内存更多的内存的平级进程的话,会将该进程杀死
selected = p;
...
}
if (selected) {
// 发送信号进行查杀
send_sig(SIGKILL, selected, 0);
}
return rem;
}
参考: https://zhuanlan.zhihu.com/p/145245419
Android lmkd 和AMS 共同维护app进程的管理
所有的APP进程都是从zygote进程fork出来的,包装成ProcessRecord记录在system_server进程的AMS的mLruProcess列表中,由AMS统一管理。
AMS 根据app的状态(前台,后台等等),更新app进程的状态,并更新进程的oom_adj,这个值会通过socket传递给lmkd进程。
lmkd
init进程fork的一个用户空间进程,方便用户空间动态调整进程的oom_score_adj 值,从而动态控制低内存时被回收的进程; 调整minfree 和adj来动态调整查杀阈值。
FWK定义的一些进程的oom_score_adj
http://androidxref.com/9.0.0_r3/xref/frameworks/base/services/core/java/com/android/server/am/ProcessList.java#69
ProcessList 中的一些常量。
// GB: 2048,3072,4096,6144,7168,8192
// HC: 8192,10240,12288,14336,16384,20480
ProcessList设置oom_adj
http://androidxref.com/9.0.0_r3/xref/frameworks/base/services/core/java/com/android/server/am/ProcessList.java#69