深入AMS源码(三)——ActivityManagerService的内存管理

1、简介

  • AMS对内存管理
  1. 当应用程序关闭后,后台对应的进程并没有真正的退出进程只是处于sleep状态,以便下次启动能快速启动,即关闭而不退出;
  2. 当系统内存不足时,AMS会回调相应的应用程序通知释放内存;
  3. 当系统内存不足时,AMS主动根据一定的优先规则退出优先级较低的进程;
  • 程序关闭而不退出

程序在退出之后不会关闭进程,当应用二次启动时如果进程还在则直接使用,此处可能存在的疑问就是进程持续存在是否影响系统的执行?事实上只是当前进程处于sleep()状态,此时只占用物理内存并不会影响前台程序使用速度,我们在启动在进程后会初始化Looper对象,Looper会循环获取消息事件,当程序关闭后消息事件为空,则进程进入sleep状态,一般来说此时100个休眠进程内不会影响运行速度,当发声用户交互、定时器中断、Binder消息时会想主线程发送消息唤醒next()方法获取事件然后执行事件处理;

所有关于Android 中的OOM机制和Android对进程的处理放在后一篇文章中分析,本篇主要分析下Android内部如何管理内存机制;

2、内存回收流程

  • 内存释放地点
  1. 在AMS中当系统内存低时,按照回收优先级释放对应进程
  2. OOM Killer 在内存紧张时会按照优先级杀死进程
  3. 在应用程序中,当AMS任务进程需要杀死时,会先回调scheduleLowMemory()方法,通知目标进程释放内存;
  • IdleHandler回收内存机制

由前面的学习知道,在Activity启动完成后回调ActivityThread.handleResumeActivity(),在方法的最后一句发送了一个Idler事件,此Idler事件会触发内存回收机制

Looper.myQueue().addIdleHandler(new Idler()); // 添加Idler事件

private final ArrayList<IdleHandler> mIdleHandlers = new ArrayList<IdleHandler>(); // IdlerHandler集合
public void addIdleHandler(@NonNull IdleHandler handler) {
    synchronized (this) {
        mIdleHandlers.add(handler); // 保存设置的Idler对象
    }
}

调用MesssageQueue中的addIdleHandler()添加Idler事件,在MesssageQueue中会将所有的Idler事件都保存在mIdleHandlers的集合中,关于Idler事件的执行放在后面分析,现在一起看一下Idler类,Idler是ActivityThread的内部类,它实现了IdleHandler接口重写queueIdle(),除此之外还有GcIdler类,在添加了Idler事件后,在从MessageQueue中获取next()时,会遍历mIdleHandlers集合中的事件,获取事件后调用queueIdle()执行事件

public static interface IdleHandler {
    boolean queueIdle();
}
private class Idler implements MessageQueue.IdleHandler {
    @Override
    public final boolean queueIdle() {
       IActivityManager am = ActivityManager.getService();
       am.activityIdle(a.token, a.createdConfig, stopProfiling); // 执行activityIdle(),调用activityIdleInternal()
       return false;
    }
}

在Idler的queueIdle()方法中,首先获取AMS对象然后调用其activityIdle()方法,这里执行到ActivityManagerService中

  • AMS.activityIdle()
public final void activityIdle(IBinder token, Configuration config) {
final long origId = Binder.clearCallingIdentity();
synchronized (this) {
    ActivityStack stack = ActivityRecord.getStackLocked(token);
    if (stack != null) {
        ActivityRecord r = mStackSupervisor.activityIdleInternalLocked(token, false /* fromTimeout */,
                        false /* processPausingActivities */, config); 
    }
}
    Binder.restoreCallingIdentity(origId);
}

在AMS.activityIdle()中先获取ActivityStack对象后,调用mStackSupervisor.activityIdleInternalLocked()方法,本段分析先暂停在这里,之后再分析activityIdleInternalLocked()中如何回收内存;

AMS中除了上面Idler事件之外,还有一个条件会触发内存回收,在前面的学习知道在执行前一个Activity的onPause()结束后,会回调AMS的completePausedLocked(),在completePausedLocked()中会将Pause的活动添加到mStoppingActivities集合中,此时会判断当处于stopping的Activity数超过3个时会发送IDLE_NOW_MSG消息处理内存,处理消息同样执行activityIdleInternal()

void addToStopping(ActivityRecord r, boolean scheduleIdle, boolean idleDelayed) {
if (!mStackSupervisor.mStoppingActivities.contains(r)) { // 加入停止活动集合
    mStackSupervisor.mStoppingActivities.add(r);
}
boolean forceIdle = mStackSupervisor.mStoppingActivities.size() > MAX_STOPPING_TO_FORCE
        || (r.frontOfTask && mTaskHistory.size() <= 1);
if (scheduleIdle || forceIdle) {
    if (!idleDelayed) {
        mStackSupervisor.scheduleIdleLocked();  //数量大于3发送IDLE事件执行内存回收,销毁Stop集合中的Activity
    } else {
        mStackSupervisor.scheduleIdleTimeoutLocked(r);
    }
} else {
    checkReadyForSleep();
}
}

void scheduleIdleTimeoutLocked(ActivityRecord next) {
    Message msg = mHandler.obtainMessage(IDLE_TIMEOUT_MSG, next);
    mHandler.sendMessageDelayed(msg, IDLE_TIMEOUT);
}
final void scheduleIdleLocked() {
    mHandler.sendEmptyMessage(IDLE_NOW_MSG);
}

scheduleIdleTimeoutLocked()和scheduleIdleLocked()都只是发送Handler事件,在处理相应的事件时都会调用activityIdleInternal()方法,在activityIdleInternal中直接调用activityIdleInternalLocked();

// scheduleIdleLocked()发送Handler事件,执行事件的回收

case IDLE_TIMEOUT_MSG: {
    activityIdleInternal((ActivityRecord) msg.obj,
            true /* processPausingActivities */);
} break;
case IDLE_NOW_MSG: {
    activityIdleInternal((ActivityRecord) msg.obj,
            false /* processPausingActivities */);
} break;
  • activityIdleInternalLocked():由上面的分析可知当两种情况出发Idler事件后,程序都会调用activityIdleInternal()方法,所有的内存处理会在此方法中进行;
final void activityIdleInternalLocked(IBinder token, boolean fromTimeout,Configuration config) {
ArrayList<ActivityRecord> stops = null;  // 保存ActivityRecord集合
ArrayList<ActivityRecord> finishes = null;
if (token != null) {
   mHandler.removeMessages(IDLE_TIMEOUT_MSG, token); // 移除超时消息,避免多次重复执行
}
int index = indexOfTokenLocked(token);
ActivityRecord r = (ActivityRecord)mHistory.get(index); // 获取当前token对应的ActivityRecord
r.idle = true;
mService.scheduleAppGcsLocked(); // 1、发送Handler事件执行客户端的内存回收
stops = processStoppingActivitiesLocked(true); // 2、将mStoppingActivity集合保存到stops,清空mStoppingActivity集合
if ((NF=mFinishingActivities.size()) > 0) {
finishes = new ArrayList<ActivityRecord>(mFinishingActivities); // 3、将mFinishingActivity保存到finishes集合中
mFinishingActivities.clear(); // 清空集合
}
            for (i=0; i<NS; i++) {
2807            ActivityRecord r = (ActivityRecord)stops.get(i); 
2808            synchronized (mService) {
2809                if (r.finishing) {
2810                    finishCurrentActivityLocked(r, FINISH_IMMEDIATELY); // 对与finish=true的,直接结束Activity
2811                } else {
2812                    stopActivityLocked(r); // 4、执行stopping集合中Activity的onStop()
2813                }
2814            }
2815        }
2819        for (i=0; i<NF; i++) {
2820            ActivityRecord r = (ActivityRecord)finishes.get(i);
2821            synchronized (mService) {
2822                destroyActivityLocked(r, true);// 5、直接destroy() 所有的Finishing的Activity
2823            }
2824        }
}
 mService.trimApplications(); // 6、执行真正的内存回收或杀死进程

在activityIdleInternalLocked()中主要执行以下操作:

  1. 发送Handler事件执行客户端的内存回收
  2. 将mStoppingActivity集合保存到stops并清空mStoppingActivity集合
  3. 将mFinishingActivity保存到finishes集合中,清空mFinishingActivities集合
  4. 执行stopping集合中Activity的onStop()方法
  5. 直接destroy() 所有的Finishing的Activity
  6. 调用trimApplications()执行真正的内存回收或杀死进程

2.1、应用程序的内存回收

  • AMS会调用scheduleAppGcLocked()方法通知客户端释放内存
 final void scheduleAppGcLocked(ProcessRecord app) {
11917        long now = SystemClock.uptimeMillis();
11918        if ((app.lastRequestedGc+GC_MIN_INTERVAL) > now) { // 1判断上次执行GC时间和现在时间慢不满足最小GC时间间隔
11919            return;
11920        }
11921        if (!mProcessesToGc.contains(app)) {
11922            addProcessToGcListLocked(app); // 2、
11923            scheduleAppGcsLocked(); // 3、
11924        }
11925    }

在scheduleAppGcLocked()中首先获取上一次执行GC的时间和当前时间,计算是否满足最小GC时间间隔,如果不满足则直接return,然后将app进程添加到将要执行GC的 mProcessToGC集合中保存,发送延时信息,通知进程执行GC

  • addProcessToGcListLocked():插入要GC的进程到mProcessToGc集合
final void addProcessToGcListLocked(ProcessRecord proc) {
11897        boolean added = false;
11898        for (int i=mProcessesToGc.size()-1; i>=0; i--) {
11899            if (mProcessesToGc.get(i).lastRequestedGc < // 适当的位置
11900                    proc.lastRequestedGc) {
11901                added = true;
11902                mProcessesToGc.add(i+1, proc);
11903                break;
11904            }
11905        }
11906        if (!added) {
11907            mProcessesToGc.add(0, proc); // 如果都没有,直接插在第一个位置
11908        }
11909    }

在addProcessToGcListLocked()中按照mProcessToGc中每个app上次GC的时间排序,将app进程插入到集合中,如果此时集合中没有对象则直接保存数据;

  • scheduleAppGcsLocked():发送延时消息通知AMS执行GC
final void scheduleAppGcsLocked() {
11875        mHandler.removeMessages(GC_BACKGROUND_PROCESSES_MSG); // 移除之前的消息事件
11876
11877        if (mProcessesToGc.size() > 0) {
11879            ProcessRecord proc = mProcessesToGc.get(0); //从mProcessToGc中去除第一个进程proc
11880            Message msg = mHandler.obtainMessage(GC_BACKGROUND_PROCESSES_MSG);
11881
11882            long when = mProcessesToGc.get(0).lastRequestedGc + GC_MIN_INTERVAL; // 设置延迟发送时间
11883            long now = SystemClock.uptimeMillis();
11884            if (when < (now+GC_TIMEOUT)) {
11885                when = now + GC_TIMEOUT; // 计算或修正时间
11886            }
11887            mHandler.sendMessageAtTime(msg, when); // 发送请求GC的消息
11888        }
11889    }

在scheduleAppGcsLocked()中从mProcessesToGc集合中取出第一个进程,计算并设置发送事件的时间最后发送事件,在Handler接收到事件后调用performAppGcsIfAppropriateLocked()方法处理事件;

  • performAppGcsIfAppropriateLocked():Handler在收到MSG消息后调用此方法
final void performAppGcsIfAppropriateLocked() {
11863        if (canGcNowLocked()) { // 判断当前是否适合执行GC操作
11864            performAppGcsLocked(); // 执行GC
11865            return;
11866        }
11868        scheduleAppGcsLocked(); //在不适合的情况下,再次发送延时消息
11869    }

private final boolean canGcNowLocked() {
11820        return mParallelBroadcasts.size() == 0 // 判断当前是否有正在执行的广播
11821                && mOrderedBroadcasts.size() == 0
                     // 判断是否处于sleep状态或具有正在交互的Activity且Activity处于idle状态
11822                && (mSleeping || (mMainStack.mResumedActivity != null && mMainStack.mResumedActivity.idle));
11824    }

在performAppGcsIfAppropriateLocked()中首先判断当前是否适合执行GC操作,主要检查是否有正在发送的广播、进程是否处于sleep、是否有正在交互的活动等,对于不能直接执行GC的继续发送延时事件,对于可执行的调用performAppGcsLocked()

  • performAppGcsLocked()
       final void performAppGcsLocked() {
11831        final int N = mProcessesToGc.size();
11835        if (canGcNowLocked()) {
11836            while (mProcessesToGc.size() > 0) { // 循环便利mProcessToGc集合中的每个进程
11837                ProcessRecord proc = mProcessesToGc.remove(0);
11838                if (proc.curRawAdj > PERCEPTIBLE_APP_ADJ || proc.reportLowMemory) { // 执行条件
11839                    if ((proc.lastRequestedGc+GC_MIN_INTERVAL) <= SystemClock.uptimeMillis()) { // 执行时间
11843                        performAppGcLocked(proc); // 执行回收内存
11844                        scheduleAppGcsLocked(); //再次发送延迟事件,每次只处理一个进程
11845                        return; // 直接return
11846                    } else {
11849                        addProcessToGcListLocked(proc);
11850                        break;
11851                    }
11852                }
11853            }
11855            scheduleAppGcsLocked(); // 发送延迟事件
11856        }
11857    }

在performAppGcsLocked()中主要从mProcessesToGc集合中取出第一个进程,然后调用performAppGcLocked()执行内存回收操作,在操作完成后再次发送延时事件,从这里可以看出GC操作每次只执行一个进程,且执行一次后会延时到下一次执行;

    final void performAppGcLocked(ProcessRecord app) {
11801        try {
11802            app.lastRequestedGc = SystemClock.uptimeMillis(); // 保存本次执行GC的时间
11803            if (app.thread != null) {
11804                if (app.reportLowMemory) { //低内存状态
11805                    app.reportLowMemory = false;
11806                    app.thread.scheduleLowMemory();  // 内存低导致内存释放
11807                } else {
11808                    app.thread.processInBackground();  //处理背景模式释放Binder内存
11809                }
11810            }
11811        } 
11814    }

在performAppGcLocked()中首先保存当前GC的时间,然后回调ApplicaitonThread的scheduleLowMemory()方法,同样方法会执行到ActivityThread.scheduleLowMemory()中,scheduleLowMemory中调用Handler发送LOW_MEMORY消息,Handler收到信息后执行handleLowMemory();

     final void handleLowMemory() {
3097        ArrayList<ComponentCallbacks> callbacks  = new ArrayList<ComponentCallbacks>();
3099
3100        synchronized (mPackages) {
               // 从mActivites集合中查找没有Finfish和Paused的Activity、Service、Provider、Application等
3101            callbacks = collectComponentCallbacksLocked(true, null);
3102        }
3103
3104        final int N = callbacks.size();
3105        for (int i=0; i<N; i++) {
3106            callbacks.get(i).onLowMemory(); // 回到所有Activity的onLowMemory()
3107        }
3110        if (Process.myUid() != Process.SYSTEM_UID) {
3111            int sqliteReleased = SQLiteDatabase.releaseMemory(); // 释放SQLite内存
3113        }
3116        Canvas.freeCaches(); // 释放Canvas
            Canvas.freeTextLayoutCaches(); // 布局引擎释放内存
3118        BinderInternal.forceGc("mem”); // 释放Binder
3119    }

在handleLowMemory()中主要执行以下几个内存释放操作:

  1. 查找所有的没有finish和pause的Activity对象,并调用其onLowMemory()通知释放内存
  2. 调用SQLiteDatabase.releaseMemory()释放数据库内存
  3. 释放Canvas内存和布局引擎内存
  4. 调用BinderInternal中方法释放Binder内存

2.2、Activity的onStop()

for (int i = 0; i < NS; i++) {
            r = stops.get(i);
            final ActivityStack stack = r.getStack();
            if (stack != null) {
                if (r.finishing) {
                    stack.finishCurrentActivityLocked(r, ActivityStack.FINISH_IMMEDIATELY, false,
                            "activityIdleInternalLocked");
                } else {
                    stack.stopActivityLocked(r);
                }
            }
        }

在处理mStopping集合中保存的活动时,此时活动都处于Paused状态,在获取到ActivityRecord之后会判断其finishing属性,finishing为true表示需要销毁此对象,然后调用ActivityStack.finishCurrentActivityLocked(),对于不想销毁的执行ActivityStack.stopActivityLocked()方法;

  • finishCurrentActivityLocked()
// 删除集合中的此Record信息
mStackSupervisor.mStoppingActivities.remove(r);
mStackSupervisor.mGoingToSleepActivities.remove(r);
mStackSupervisor.mActivitiesWaitingForVisibleActivity.remove(r);

if (mode == FINISH_IMMEDIATELY
                || (prevState == PAUSED
                    && (mode == FINISH_AFTER_PAUSE || inPinnedWindowingMode()))
                || finishingActivityInNonFocusedStack
                || prevState == STOPPING
                || prevState == STOPPED
                || prevState == ActivityState.INITIALIZING) {
            r.makeFinishingLocked();
            boolean activityRemoved = destroyActivityLocked(r, true, "finish-imm:" + reason);
  if (finishingActivityInNonFocusedStack) {
                mStackSupervisor.ensureVisibilityAndConfig(next, mDisplayId,
                        false /* markFrozenIfConfigChanged */, true /* deferResume */);
            }
            if (activityRemoved) {
                mStackSupervisor.resumeFocusedStackTopActivityLocked();
            }
            return activityRemoved ? null : r;
        }

在finishCurrentActivityLocked()中首先从保存信息的集合中移除信息面,因为此活动即将被销毁,然后判断当前活动的状态并调用ActivityRecord.makeFinishingLocked(),最后调用destroyActivityLocked()销毁Activity,关于destroyActivityLocked()放在之后分析,在销毁活动之后又调用resumeFocusedStackTopActivityLocked()方法显示栈顶的活动;

  • stopActivityLocked()
if (!r.visible) {
                    r.setVisible(false);
                }

 adjustFocusedActivityStack(r, "stopActivity"); //1
 //2
  mService.getLifecycleManager().scheduleTransaction(r.app.thread, r.appToken,
                        StopActivityItem.obtain(r.visible, r.configChangeFlags));
                        //3
                Message msg = mHandler.obtainMessage(STOP_TIMEOUT_MSG, r);
                mHandler.sendMessageDelayed(msg, STOP_TIMEOUT);

在stopActivityLocked()中主要执行三件事:

  1. 首先根据要stop的活动调整ActivityStack和当前交互的任务栈
  2. 使用LifecycleManager执行StopActivityItem,在StopActivityItem中会通过ActivityThread类调用Activity的onStop()
  3. 发送Handler事件,防止stop事件超时

2.3、Activity的Finish()

for (int i = 0; i < NF; i++) {
            r = finishes.get(i);
            final ActivityStack stack = r.getStack();
            if (stack != null) {
                activityRemoved |= stack.destroyActivityLocked(r, true, "finish-idle");
            }
        }
  • destroyActivityLocked()
cleanUpActivityLocked(r, false, false);

 final boolean hadApp = r.app != null; // 1、
if (hadApp) {
r.app.activities.remove(r); //2、
 mService.getLifecycleManager().scheduleTransaction(r.app.thread, r.appToken,
                        DestroyActivityItem.obtain(r.finishing, r.configChangeFlags)); //3、
 Message msg = mHandler.obtainMessage(DESTROY_TIMEOUT_MSG, r); //4、
                mHandler.sendMessageDelayed(msg, DESTROY_TIMEOUT);
}else {
            if (r.finishing) {
                removeActivityFromHistoryLocked(r, reason + " hadNoApp");
                removedFromHistory = true; //5、
            } else {
                r.setState(DESTROYED, "destroyActivityLocked. not finishing and had no app"); //6、
                r.app = null;
            }
        }
if (!mLRUActivities.remove(r) && hadApp) {  //7、
            Slog.w(TAG, "Activity " + r + " being finished, but not in LRU list");
        }

在destroyActivityLocked()中执行:

  1. 调用cleanUpActivityLocked清除集合中保存的Activity数据
  2. 判断当前Activity是否存在进程信息,从activities中清除ActivityRecord
  3. 使用LifecycleManager执行Activity的onDestory()
  4. 对于不包含进程信息的,则直接从历史记录中删除信息,并设置State为DESTORYED,
  5. 从mLRUActivities集合中清除Activity信息,之后activity就完整的删除了;

总结以下:在AMS对Activity调度管理中包含着对程序内存的处理,在resume完目标Activity后即表示活动已经启动完毕,之后会添加内存回收相关的Idler事件,在事件执行时会触发Activity的低内存状态,通知应用程序释放内存,客户端在收到消息后会释放程序内存、数据库内存、Binder内存等,在处理内存之后AMS会对目前Stopping和finishing中的活动,执行对应的stop()和finish()方法;

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章