深入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()方法;

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