美文网首页
lowmemorykiller总结

lowmemorykiller总结

作者: Stan_Z | 来源:发表于2018-01-07 22:03 被阅读359次

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

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

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

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

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

    ADJ级别 取值 解释
    UNKNOWN_ADJ 16 一般指将要会缓存进程,无法获取确定值
    CACHED_APP_MAX_ADJ 15 不可见进程的adj最大值
    CACHED_APP_MIN_ADJ 9 不可见进程的adj最小值
    SERVICE_B_ADJ 8 B List中的Service(较老的、使用可能性更小)
    PREVIOUS_APP_ADJ 7 上一个App的进程(往往通过按返回键)
    HOME_APP_ADJ 6 Home进程
    SERVICE_ADJ 5 服务进程(Service process)
    HEAVY_WEIGHT_APP_ADJ 4 后台的重量级进程,system/rootdir/init.rc文件中设置
    BACKUP_APP_ADJ 3 备份进程
    PERCEPTIBLE_APP_ADJ 2 可感知进程,比如后台音乐播放
    VISIBLE_APP_ADJ 1 可见进程(Visible process)
    FOREGROUND_APP_ADJ 0 前台进程(Foreground process)
    PERSISTENT_SERVICE_ADJ -11 关联着系统或persistent进程
    PERSISTENT_PROC_ADJ -12 系统persistent进程,比如telephony
    SYSTEM_ADJ -16 系统进程
    NATIVE_ADJ -17 native进程(不被系统管理)

    然后,我们要了解两个问题:
    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更新并保存。

    总结为如下表格:

    AMS ProcessList lmkd.c 描述
    applyOomAdjLocked setOomAdj LMK_PROCPRIO 设置进程adj
    updateConfiguration updateOomLevels LMK_TARGET 更新oom_adj
    cleanUpApplicationRecordLocked/handleAppDiedLocked remove LMK_PROCREMOVE 移除进程
    Lmkd.c 对应方法 执行动作
    LMK_PROCPRIO cmd_procprio 写/proc/<pid>/oom_score_adj
    LMK_TARGET cmd_target 写/sys/module/lowmemorykiller/parameters/minfree写/sys/module/lowmemorykiller/parameters/adj
    LMK_PROCREMOVE cmd_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.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

    相关文章

      网友评论

          本文标题:lowmemorykiller总结

          本文链接:https://www.haomeiwen.com/subject/cmvmnxtx.html