1、簡介
- AMS對內存管理
- 當應用程序關閉後,後臺對應的進程並沒有真正的退出進程只是處於sleep狀態,以便下次啓動能快速啓動,即關閉而不退出;
- 當系統內存不足時,AMS會回調相應的應用程序通知釋放內存;
- 當系統內存不足時,AMS主動根據一定的優先規則退出優先級較低的進程;
- 程序關閉而不退出
程序在退出之後不會關閉進程,當應用二次啓動時如果進程還在則直接使用,此處可能存在的疑問就是進程持續存在是否影響系統的執行?事實上只是當前進程處於sleep()狀態,此時只佔用物理內存並不會影響前臺程序使用速度,我們在啓動在進程後會初始化Looper對象,Looper會循環獲取消息事件,當程序關閉後消息事件爲空,則進程進入sleep狀態,一般來說此時100個休眠進程內不會影響運行速度,當發聲用戶交互、定時器中斷、Binder消息時會想主線程發送消息喚醒next()方法獲取事件然後執行事件處理;
所有關於Android 中的OOM機制和Android對進程的處理放在後一篇文章中分析,本篇主要分析下Android內部如何管理內存機制;
2、內存回收流程
- 內存釋放地點
- 在AMS中當系統內存低時,按照回收優先級釋放對應進程
- OOM Killer 在內存緊張時會按照優先級殺死進程
- 在應用程序中,當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()中主要執行以下操作:
- 發送Handler事件執行客戶端的內存回收
- 將mStoppingActivity集合保存到stops並清空mStoppingActivity集合
- 將mFinishingActivity保存到finishes集合中,清空mFinishingActivities集合
- 執行stopping集合中Activity的onStop()方法
- 直接destroy() 所有的Finishing的Activity
- 調用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()中主要執行以下幾個內存釋放操作:
- 查找所有的沒有finish和pause的Activity對象,並調用其onLowMemory()通知釋放內存
- 調用SQLiteDatabase.releaseMemory()釋放數據庫內存
- 釋放Canvas內存和佈局引擎內存
- 調用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()中主要執行三件事:
- 首先根據要stop的活動調整ActivityStack和當前交互的任務棧
- 使用LifecycleManager執行StopActivityItem,在StopActivityItem中會通過ActivityThread類調用Activity的onStop()
- 發送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()中執行:
- 調用cleanUpActivityLocked清除集合中保存的Activity數據
- 判斷當前Activity是否存在進程信息,從activities中清除ActivityRecord
- 使用LifecycleManager執行Activity的onDestory()
- 對於不包含進程信息的,則直接從歷史記錄中刪除信息,並設置State爲DESTORYED,
- 從mLRUActivities集合中清除Activity信息,之後activity就完整的刪除了;
總結以下:在AMS對Activity調度管理中包含着對程序內存的處理,在resume完目標Activity後即表示活動已經啓動完畢,之後會添加內存回收相關的Idler事件,在事件執行時會觸發Activity的低內存狀態,通知應用程序釋放內存,客戶端在收到消息後會釋放程序內存、數據庫內存、Binder內存等,在處理內存之後AMS會對目前Stopping和finishing中的活動,執行對應的stop()和finish()方法;