Android Gems — Android的LowMemoryKiller杀进程策略

Android系统的LowMemoryKiller(LMK)利用kernel的shrinker机制,根据进程的oom_adj值决定何时杀掉进程。当内核回收内存时,LMK依据oom_adj阈值发送SIGKILL信号。oom_adj值范围从-17到16,数值越小,进程越重要,越不易被杀。系统通过调整此值来定制杀进程策略,例如,前台应用的oom_adj值会降低至0,确保其优先级。因此,负值oom_adj的应用比前台应用更安全。
摘要由CSDN通过智能技术生成

Anroid的杀进程策略是基于kernel里的LowMemoryKiller模块,LMK的实现在这里不展开分析,大致的原理就是LMK注册了内核的shrinker(lowmem_shrinker),内核线程kswapd,在linux回收内存分页的时候,通过shrinker回调回来给LMK。LMK根据每个进程的oom_adj值,将大于某个阈值的进程都发送SIGKILL信号杀掉。oom_adj的阈值因内存情况不同而不同,具体的对应关系可以查看/sys/module/lowmemorykiller/parameters/adj和/sys/module/lowmemorykiller/parameters/minfree这两个文件。oom_adj的值从-17到16,值越小,代表越重要,越晚被杀,比如一个应用如果在前台的时候,oom_adj的值就会减到0。也就是说设为负值的那些应用,会比前台应用还晚被杀。于是,系统杀进程的策略就可以通过调整每个进程的oom_adj的值来实现。

oom_adj的值有如下类:

    // 不可见的Activity
    static final int CACHED_APP_MAX_ADJ = 15;
    static final int CACHED_APP_MIN_ADJ = 9;

   // 比较老的Service
    static final int SERVICE_B_ADJ = 8;

    // 上一个应用,这样在做任务切换,或者返回的时候,能够快速载入
    static final int PREVIOUS_APP_ADJ = 7;

   // 桌面 App
    static final int HOME_APP_ADJ = 6;

   // Service
    static final int SERVICE_ADJ = 5;

    // 重量级应用,早期版本可以在manifest里加cantSaveState来声明,新版已经注释了,目前没看到哪里可以设置
    static final int HEAVY_WEIGHT_APP_ADJ = 4;

    // 备份代理应用,manifest里Application标签里可以声明backAgent
    static final int BACKUP_APP_ADJ = 3;

    // 可感知的App,比如有Pause状态的Activity,Stopping状态的Activity,被一个可见的进程BindService的进程等
    static final int PERCEPTIBLE_APP_ADJ = 2;

    // 前台可见的Activity,
    static final int VISIBLE_APP_ADJ = 1;

   // 前台App,包括Top App,Instrumentation Test App,正在接收broadcast的App,正在执行的Service等
    static final int FOREGROUND_APP_ADJ = 0;

   //  被Persist App BindService的进程
    static final int PERSISTENT_SERVICE_ADJ = -11;

   //  声明了persist的进程
    static final int PERSISTENT_PROC_ADJ = -12;

    // 系统进程,比如system server
    static final int SYSTEM_ADJ = -16;

    // 不被系统管的Native进程,比如/system/bin下运行的那些服务(surfaceflinger etc)
    static final int NATIVE_ADJ = -17;

oom_adj的值受很多因素影响:应用是否有activity,activity是否可见,是否有service,service是否被bind的其他进程的oom_adj等等。在Framework里oom_adj的调整主要由ActivityManagerService这个类负责,任何可能会影响到进程oom_adj的值的情况,就会调用updateOomAdjLocked来更新各进程的oom_adj值,比如:
1,Activity切换
2,Service start/stop/bind
3,Broadcast分发处理
updateOomAdjLocked会遍历当前进程列表,对每个进程ProcessRecord都调用computeOomAdjLocked来重新计算oom_adj,最后applyOomAdjLocked来使oom_adj生效。
我们看看updateOomAdjLocked的实现:
final void updateOomAdjLocked() {
        final ActivityRecord TOP_ACT = resumedAppLocked();
        final ProcessRecord TOP_APP = TOP_ACT != null ? TOP_ACT.app : null;
        final long now = SystemClock.uptimeMillis();
        final long oldTime = now - ProcessList.MAX_EMPTY_TIME;
        final int N = mLruProcesses.size();

        ......
        ......
        
        for (int i=N-1; i>=0; i--) {
            ProcessRecord app = mLruProcesses.get(i);
            // 找到最早的一次service活动时间
            if (mEnableBServicePropagation && app.serviceb
                    && (app.curAdj == ProcessList.SERVICE_B_ADJ)) {
                numBServices++;
                for (int s = app.services.size() - 1; s >= 0; s--) {
                    ServiceRecord sr = app.services.valueAt(s);
                    if (DEBUG_OOM_ADJ) Slog.d(TAG,"app.processName = " + app.processName
                            + " serviceb = " + app.serviceb + " s = " + s + " sr.lastActivity = "
                            + sr.lastActivity + " packageName = " + sr.packageName
                            + " processName = " + sr.processName);
                    if (SystemClock.uptimeMillis() - sr.lastActivity
                            < mMinBServiceAgingTime) {
                        if (DEBUG_OOM_ADJ) {
                            Slog.d(TAG,"Not aged enough!!!");
                        }
                        continue;
                    }
                    if (serviceLastActivity == 0) {
                        serviceLastActivity = sr.lastActivity;
                        selectedAppRecord = app;
                    } else if (sr.lastActivity < serviceLastActivity) {
                        serviceLastActivity = sr.lastActivity;
                        selectedAppRecord = app;
                    }
                }
            }
            if (DEBUG_OOM_ADJ && selectedAppRecord != null) Slog.d(TAG,
                    "Identified app.processName = " + selectedAppRecord.processName
                    + " app.pid = " + selectedAppRecord.pid);
            if (!app.killedByAm && app.thread != null) {
                app.procStateChanged = false;
               // 重新计算进程app的oom_adj
                computeOomAdjLocked(app, ProcessList.UNKNOWN_ADJ, TOP_APP, true, now);

                // If we haven't yet assigned the final cached adj
                // to the process, do that now.
                // 如果没找到对应的oom_adj,那么根据app的进程状态,如果有activity存在,那么oom_adj设为curCachedAdj,
                // 否则就是empty进程,讲oom_adj设为curEmptyAdj
                if (app.curAdj >= ProcessList.UNKNOWN_ADJ) {
                    switch (app.curProcState) {
                        case ActivityManager.PROCESS_STATE_CACHED_ACTIVITY:
                        case ActivityManager.PROCESS_STATE_CACHED_ACTIVITY_CLIENT:
                            // This process is a cached process holding activities...
                            // assign it the next cached value for that type, and then
                            // step that cached level.
                            app.curRawAdj = curCachedAdj;
                            app.curAdj = app.modifyRawOomAdj(curCachedAdj);
                            if (DEBUG_LRU && false) Slog.d(TAG_LRU, "Assigning activity LRU #" + i
                                    + " adj: " + app.curAdj + " (curCachedAdj=" + curCachedAdj
                                    + ")");
                            if (curCachedAdj != nextCachedAdj) {
                                stepCached++;
                                if (stepCached >= cachedFactor) {
                                    stepCached = 0;
                                    curCachedAdj = nextCachedAdj;
                                    nextCachedAdj += 2;
                                    if (nextCachedAdj > ProcessList.CACHED_APP_
  • 1
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值