lowmemorykiller总结

版权声明:本文为作者原创,转载必须注明出处。
转载请注明出处:https://www.jianshu.com/p/09922ab0390b

我们知道,从zygote孵化出来的进程都会记录在ActivityManagerService.mLruProcesses列表中,由ActivityManagerService进行统一管理,ActivityManagerService核心业务之一便是时时更新进程的状态,根据状态计算出进程对应的OomAdj值,这个值会传递到kernel中去,kernel有个低内存回收机制,在内存达到一定阀值时会触发清理OomAdj值高的进程,这边是Lowmemorykiller工作原理。

首先来看一下整体的流程:

《lowmemorykiller总结》

我们都知道,AMS负责了系统中四大组件的启动、切换、调度以及应用进程管理和调度工作。在APP使用过程中,AMS会根据四大组件关键生命周期,在mLruProcesses中时时地设定对应进程的adj值(更新进程优先级),在内存低于lowmemorykiller杀进程的阈值时,lowmemorykiller会选择adj优先级最大(如果adj相等选择同adj中内存占用最大)的进程杀掉,释放内存。

其次,了解下定义在ProcessList.java文件的ADJ级别,oom_adj划分为16级,从-17到16之间取值。越大优先级越低

ADJ级别取值解释
UNKNOWN_ADJ16一般指将要会缓存进程,无法获取确定值
CACHED_APP_MAX_ADJ15不可见进程的adj最大值
CACHED_APP_MIN_ADJ9不可见进程的adj最小值
SERVICE_B_ADJ8B List中的Service(较老的、使用可能性更小)
PREVIOUS_APP_ADJ7上一个App的进程(往往通过按返回键)
HOME_APP_ADJ6Home进程
SERVICE_ADJ5服务进程(Service process)
HEAVY_WEIGHT_APP_ADJ4后台的重量级进程,system/rootdir/init.rc文件中设置
BACKUP_APP_ADJ3备份进程
PERCEPTIBLE_APP_ADJ2可感知进程,比如后台音乐播放
VISIBLE_APP_ADJ1可见进程(Visible process)
FOREGROUND_APP_ADJ0前台进程(Foreground process)
PERSISTENT_SERVICE_ADJ-11关联着系统或persistent进程
PERSISTENT_PROC_ADJ-12系统persistent进程,比如telephony
SYSTEM_ADJ-16系统进程
NATIVE_ADJ-17native进程(不被系统管理)

然后,我们要了解两个问题:
1)阈值是怎么设定的?

AMS updateConfiguration方法是设定阈值的入口,在AMS初始化时执行一次,通过调用ProcessList中updateOomLevels方法,计算出阈值adj 和 minfree 并通过Lmkd.c写入文件中保存。

2)adj的更新流程是怎样的?

AMS调整进程的adj有3大护法:

  • computeOomAdjLocked:计算adj(对优先级高于cache和empty的进程进行adj的分配)。该方法执行是在updateOomAdjLocked中。
  • updateOomAdjLocked:更新adj(分配computeOomAdjLocked没有处理的cache和empty优先级的进程adj)
    AMS updateOomAdjLocked方法的执行场景:
    1) Activity的start/resume/finish;
    2) Service的start/bind/unbind;
    3) broadcast的分发/处理;
    4) contentprovider的发布/移除/获取;
    5) 进程的kill/attach等。
  • applyOomAdjLocked:应用adj,直接保存对应进程的adj:ProcessList执行setOomAdj方法,通过socket传送数据给Lmkd.c,最终Lmkd.c针对每一个进程创建单独文件并写入adj。该方法执行是在updateOomAdjLocked中,最终通过它把computeOomAdjLocked和updateOomAdjLocked计算好的adj更新并保存。

总结为如下表格:

AMSProcessListlmkd.c描述
applyOomAdjLockedsetOomAdjLMK_PROCPRIO设置进程adj
updateConfigurationupdateOomLevelsLMK_TARGET更新oom_adj
cleanUpApplicationRecordLocked/handleAppDiedLockedremoveLMK_PROCREMOVE移除进程
Lmkd.c对应方法执行动作
LMK_PROCPRIOcmd_procprio写/proc/<pid>/oom_score_adj
LMK_TARGETcmd_target写/sys/module/lowmemorykiller/parameters/minfree写/sys/module/lowmemorykiller/parameters/adj
LMK_PROCREMOVEcmd_procremove删除/proc/<pid>

查看系统阀值: adb shell cat /sys/module/lowmemorykiller/parameters/minfree

18432,23040,27648,32256,55296,80640
以上数字的单位是page. 1 page = 4 kb
对应的就是(MB): 72,90,108,216,216,315

为了更直观地了解执行流程,以applyOomAdjLocked过程为例,以下是时序图:

《lowmemorykiller总结》

最终通过lowmemorykiller.c的核心方法:lowmen_scan执行杀进程:
监测到当前内存低于系统阈值(取出保存的minfree做对比),则会在大于等于该阈值的adj中寻找最大的(读取/proc/<pid>/oom_score_adj每个进程的adj值),出现相等的情况,则挑选内存占用最大的进程作为kill的目标,最终通过信号将其杀掉。

此文抛砖引玉,目的只是简单介绍lowmemorykiller的执行原理和流程,并没有贴代码也没有一行行地去抠代码细节,目的是梳理下框架,也是作为一个备忘的小总结。

想详细了解lowmemorykiller的朋友推荐看看以下博文:
http://gityuan.com/2016/09/17/android-lowmemorykiller/
http://blog.csdn.net/happylishang/article/details/54408733

    原文作者:ZHTo0
    原文地址: https://www.jianshu.com/p/09922ab0390b
    本文转自网络文章,转载此文章仅为分享知识,如有侵权,请联系博主进行删除。
点赞