- 相關(guān)推薦
Android操作系統(tǒng)的內(nèi)存回收的策略是什么
Android 是一款基于 Linux 內(nèi)核,面向移動終端的操作系統(tǒng)。為適應(yīng)其作為移動平臺操作系統(tǒng)的特殊需要,谷歌對其做了特別的設(shè)計與優(yōu)化,使應(yīng)用程序關(guān)閉但不退出,并由操作系統(tǒng)進行進程的回收管理。本文在 Application Framework 與 Linux 內(nèi)核兩個層次上,以進程為粒度,對 Android 操作系統(tǒng)的進程資源回收機制進行了剖析。讀者可以從本文獲得對 Android 應(yīng)用程序的生存周期的進一步理解,從而更加合理、高效地構(gòu)建應(yīng)用程序。
Android 操作系統(tǒng)中的內(nèi)存回收可分為兩個層次:
1、默認內(nèi)存回收、即Application Framework 層的默認回收。
2、內(nèi)核級內(nèi)存回收。
Linux 內(nèi)核中的內(nèi)存回收 lowmemorykiller、OOM_killer。
默認內(nèi)存回收:(代碼可查閱 ActivityManagerService.java類)回收動作入口activityIdleInternal()。
Android 系統(tǒng)中內(nèi)存回收的觸發(fā)點大致可分為三種情況。
第一,用戶程序調(diào)用 StartActivity(), 使當前活動的 Activity 被覆蓋;
第二,用戶按 back 鍵,退出當前應(yīng)用程序;第三,啟動一個新的應(yīng)用程序。
這些能夠觸發(fā)內(nèi)存回收的事件最終調(diào)用的函數(shù)接口就是 activityIdleInternal()。當 ActivityManagerService 接收到異步消息 IDLE_TIMEOUT_MSG 或者 IDLE_NOW_MSG 時,activityIdleInternal() 將會被調(diào)用。 IDLE_NOW_MSG 由 Activity 的切換以及 Activiy 焦點的改變等事件引發(fā),IDLE_TIMEOUT_MSG 在 Activity 啟動超時的情況下引發(fā),一般這個超時時間設(shè)為 10s,如果 10s 之內(nèi)一個 Activity 依然沒有成功啟動,那么將發(fā)送異步消息 IDLE_TIMEOUT_MSG 進行資源回收。activityIdleInternal() 的主要任務(wù)是改變系統(tǒng)中 Activity 的狀態(tài)信息,并將其添加到不同狀態(tài)列表中。它的主要工如下:
首先,調(diào)用 scheduleAppGcsLocked() 方法通知所有進行中的任務(wù)進行垃圾回收。scheduleAppGcsLocked() 將進行調(diào)度 JVM 的 garbage collect,回收一部分內(nèi)存空間,這里僅僅是通知每個進程自行進程垃圾檢查并調(diào)度回收時間,而非同步回收。
然后,取出 mStoppingActivities 和 mFinishigActivities 列表中的所有內(nèi)容,暫存在臨時變量中。這兩個列表分別存儲了當前狀態(tài)為 stop 和 finishi 的 activity 對象。對于 stop 列表,如果其中的 activity 的 finish 狀態(tài)為 true,判斷是不是要立即停止,如果要立即停止則調(diào)用 destroyActivityLocked() 通知目標進程調(diào)用 onDestroy() 方法,否則,先調(diào)用resumeTopActivity() 運行下一個 Activity。如果 finish 狀態(tài)為 false,則調(diào)用 stopActivityLocked() 通知客戶進程停止該 Activity,這種情況一般發(fā)生在調(diào)用 startActivity() 后。對于 finish 列表,直接調(diào)用 destroyActivityLocked() 通知客戶進程銷毀目標 Activity。這里的 destroyActivityLocked 等函數(shù)并沒有真正意義上改變內(nèi)存的使用,只是將其狀態(tài)改變?yōu)椤霸试S回收”,真正的回收在下面即將調(diào)用的 trimApplications() 函數(shù)中。
private final void trimApplications() {synchronized (this) {// First remove any unused application processes whose package// has been removed.for (i=mRemovedProcesses.size()-1; i>=0; i--) {(1)//kill process;}if (!updateOomAdjLocked()) {(2)//do something default}// Finally, if there are too many activities now running, try to// finish as many as we can to get back down to the limit.(3)do something}}
(1)當程序執(zhí)行到 trimApplications() 之后,首先檢查 mRemovedProcesses 列表中的進程。mRemovedProcesses 列表中主要包含了 crash 的進程、5 秒內(nèi)沒有響應(yīng)并被用戶選在強制關(guān)閉的進程、以及應(yīng)用開發(fā)這調(diào)用 killBackgroundProcess 想要殺死的進程。調(diào)用 Process.killProcess 將所有此類進程全部殺死。
。2)調(diào)用 updateOomAdjLocked() 函數(shù),若成功返回,說明 Linux 內(nèi)核支持 setOomAdj() 接口,updateOomAdjLocked 將修改 adj 的值并通知 linux 內(nèi)核,內(nèi)核根據(jù) adj 值以及內(nèi)存使用情況動態(tài)管理進程資源(lowmemorykiller 和 oom_killer)。若 updateOomAdjLocked() 返回為假,則表示當前系統(tǒng)不支持 setOomAdj() 接口,將在本地進行默認的資源回收。
。3)最后,如果當前依然運行了過多的 Activity,對多余的 Activity 進行回收。 trimApplications() 的大多數(shù)的代碼都在處理 Oom_killer 不存在情況下的默認資源回收,下面對其默認回收過程(即代碼中標記(2)的位置)進行進一步分析。其回收過程可大致描述如下。
步驟一,獲取當前所有運行的進程 mLruProcesses,mLruProcesses 中的排序規(guī)則是按最近使用時間。對 mLruProcesses 中不能被關(guān)閉的進程進行計數(shù),這些不能被關(guān)閉的進程包括運行 service 的進程,運行broadcast receiver 的進程等。
步驟二, 設(shè)當前最大運行進程數(shù) curMaxProcs = curMaxProcs + numServiceProcs(即默認最大進程數(shù)與運行 Service 的進程數(shù)之和),如果當前進程的數(shù)量 mRemovedProcesses.size() 大于這個值,則遍歷所有當前運行的進程,殺死符合條件的那些進程并釋放內(nèi)存。進程被殺死的條件是:必須是非 persistent 進程,即非系統(tǒng)進程,必須是空進程,即進程中沒有任何 activity 存在。如果殺死存在 Activity 的進程,有可能關(guān)閉用戶正在使用的程序,或者使應(yīng)用程序恢復(fù)的時延變大,從而影響用戶體驗;必須無 broadcast receiver。運行 broadcast receiver 一般都在等待一個事件的發(fā)生,用戶并不希望此類程序被系統(tǒng)強制關(guān)閉;進程中 service 的數(shù)量必須為 0。存在 service 的進程很有可能在為一個或者多個程序提供某種服務(wù),如 GPS 定位服務(wù)。殺死此類進程將使其他進程無法正常服務(wù)。
步驟三,再次檢查當前運行的進程,如果 mRemovedProcesses.size() 仍然大于 curMaxProcs,則放寬條件再次進行回收。
步驟四,上面 3 個過程都是針對整個 process 進行的資源回收。在以上過程執(zhí)行完畢之后,將在更小的粒度上對 Activity 的資源進行回收。與上面所述類似,列表 mLRUActivities 存儲了當前所有運行中的 Activity,排序規(guī)則同樣為最少訪問原則。mLRUActivities.size() 返回系統(tǒng)中運行的 Activity 的數(shù)量,當其大于 MAX_ACTIVITIES(MAX_ACTIVITIES 是一個常量,一般值為 20,代表系統(tǒng)中最大允許同時存在的 Activity)時。將回收部分滿足條件的 Activity 以減少內(nèi)存的使用。 這里回收的只是 Activity 的內(nèi)存資源,并不會殺死進程,也不會影響進程的運行。當進程需要調(diào)用被殺掉的 Activity 時,可以從保存的狀態(tài)中回復(fù),當然可能需要相對長一點的時延。
Linux 內(nèi)核中的內(nèi)存回收
lowmemorykiller
trimApplications() 函數(shù)中會執(zhí)行一個叫做 updateOomAdjLocked() 的函數(shù),如果返回 false,則執(zhí)行默認回收,若返回 true 則不執(zhí)行默認內(nèi)存回收。
updateOomAdjLocked 將針對每一個進程更新一個名為 adj 的變量,并將其告知 Linux 內(nèi)核,內(nèi)核維護一個包含 adj 的數(shù)據(jù)結(jié)構(gòu)(即進程表),并通過 lowmemorykiller 檢查系統(tǒng)內(nèi)存的使用情況,在內(nèi)存不足的情況下殺死一些進程并釋放內(nèi)存。
由于 Android 操作系統(tǒng)中的所有應(yīng)用程序都運行在獨立的 Dalvik 虛擬機環(huán)境中,Linux 內(nèi)核無法獲知每個進程的運行狀態(tài),也就無法為每個進程維護一個合適的 adj 值,因此,Android Application Framework 中必須提供一套機制以動態(tài)的更新每個進程的 adj。這就是 updateOomAdjLocked()。
Android 基于進程中運行的組件及其狀態(tài)規(guī)定了默認的五個回收優(yōu)先級:
IMPORTANCE_FOREGROUND:
IMPORTANCE_VISIBLE:
IMPORTANCE_SERVICE:
IMPORTANCE_BACKGROUND:
IMPORTANCE_EMPTY:
【Android操作系統(tǒng)的內(nèi)存回收的策略是什么】相關(guān)文章:
Java內(nèi)存回收07-17
關(guān)于android操作系統(tǒng)05-30
Android操作系統(tǒng)的發(fā)展與未來08-19
android操作系統(tǒng)的設(shè)置過程09-13
操作系統(tǒng)內(nèi)存優(yōu)化的攻略總結(jié)10-31