Android教程網
  1. 首頁
  2. Android 技術
  3. Android 手機
  4. Android 系統教程
  5. Android 游戲
 Android教程網 >> Android技術 >> 關於Android編程 >> Android操作系統之內存回收策略

Android操作系統之內存回收策略

編輯:關於Android編程

Android 是一款基於 Linux 內核,面向移動終端的操作系統。為適應其作為移動平台操作系統的特殊需要,谷歌對其做了特別的設計與優化,使應用程序關閉但不退出,並由操作系統進行進程的回收管理。本文在 Application Framework 與 Linux 內核兩個層次上,以進程為粒度,對 Android 操作系統的進程資源回收機制進行了剖析。讀者可以從本文獲得對 Android 應用程序的生存周期的進一步理解,從而更加合理、高效地構建應用程序。

Android 操作系統中的內存回收可分為兩個層次:

1、默認內存回收、即Application Framework 層的默認回收。

2、內核級內存回收。

Linux 內核中的內存回收 lowmemorykiller、OOM_killer。

默認內存回收:(代碼可查閱 ActivityManagerService.java類)回收動作入口activityIdleInternal()。

Android 系統中內存回收的觸發點大致可分為三種情況。

第一,用戶程序調用 StartActivity(), 使當前活動的 Activity 被覆蓋;

第二,用戶按 back 鍵,退出當前應用程序;第三,啟動一個新的應用程序。

這些能夠觸發內存回收的事件最終調用的函數接口就是 activityIdleInternal()。當 ActivityManagerService 接收到異步消息 IDLE_TIMEOUT_MSG 或者 IDLE_NOW_MSG 時,activityIdleInternal() 將會被調用。 IDLE_NOW_MSG 由 Activity 的切換以及 Activiy 焦點的改變等事件引發,IDLE_TIMEOUT_MSG 在 Activity 啟動超時的情況下引發,一般這個超時時間設為 10s,如果 10s 之內一個 Activity 依然沒有成功啟動,那麼將發送異步消息 IDLE_TIMEOUT_MSG 進行資源回收。activityIdleInternal() 的主要任務是改變系統中 Activity 的狀態信息,並將其添加到不同狀態列表中。它的主要工如下:

首先,調用 scheduleAppGcsLocked() 方法通知所有進行中的任務進行垃圾回收。scheduleAppGcsLocked() 將進行調度 JVM 的 garbage collect,回收一部分內存空間,這裡僅僅是通知每個進程自行進程垃圾檢查並調度回收時間,而非同步回收。

然後,取出 mStoppingActivities 和 mFinishigActivities 列表中的所有內容,暫存在臨時變量中。這兩個列表分別存儲了當前狀態為 stop 和 finishi 的 activity 對象。對於 stop 列表,如果其中的 activity 的 finish 狀態為 true,判斷是不是要立即停止,如果要立即停止則調用 destroyActivityLocked() 通知目標進程調用 onDestroy() 方法,否則,先調用resumeTopActivity() 運行下一個 Activity。如果 finish 狀態為 false,則調用 stopActivityLocked() 通知客戶進程停止該 Activity,這種情況一般發生在調用 startActivity() 後。對於 finish 列表,直接調用 destroyActivityLocked() 通知客戶進程銷毀目標 Activity。這裡的 destroyActivityLocked 等函數並沒有真正意義上改變內存的使用,只是將其狀態改變為“允許回收”,真正的回收在下面即將調用的 trimApplications() 函數中。

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)當程序執行到 trimApplications() 之後,首先檢查 mRemovedProcesses 列表中的進程。mRemovedProcesses 列表中主要包含了 crash 的進程、5 秒內沒有響應並被用戶選在強制關閉的進程、以及應用開發這調用 killBackgroundProcess 想要殺死的進程。調用 Process.killProcess 將所有此類進程全部殺死。

(2)調用 updateOomAdjLocked() 函數,若成功返回,說明 Linux 內核支持 setOomAdj() 接口,updateOomAdjLocked 將修改 adj 的值並通知 linux 內核,內核根據 adj 值以及內存使用情況動態管理進程資源(lowmemorykiller 和 oom_killer)。若 updateOomAdjLocked() 返回為假,則表示當前系統不支持 setOomAdj() 接口,將在本地進行默認的資源回收。

(3)最後,如果當前依然運行了過多的 Activity,對多余的 Activity 進行回收。 trimApplications() 的大多數的代碼都在處理 Oom_killer 不存在情況下的默認資源回收,下面對其默認回收過程(即代碼中標記(2)的位置)進行進一步分析。其回收過程可大致描述如下。

步驟一,獲取當前所有運行的進程 mLruProcesses,mLruProcesses 中的排序規則是按最近使用時間。對 mLruProcesses 中不能被關閉的進程進行計數,這些不能被關閉的進程包括運行 service 的進程,運行broadcast receiver 的進程等。

步驟二, 設當前最大運行進程數 curMaxProcs = curMaxProcs + numServiceProcs(即默認最大進程數與運行 Service 的進程數之和),如果當前進程的數量 mRemovedProcesses.size() 大於這個值,則遍歷所有當前運行的進程,殺死符合條件的那些進程並釋放內存。進程被殺死的條件是:必須是非 persistent 進程,即非系統進程,必須是空進程,即進程中沒有任何 activity 存在。如果殺死存在 Activity 的進程,有可能關閉用戶正在使用的程序,或者使應用程序恢復的時延變大,從而影響用戶體驗;必須無 broadcast receiver。運行 broadcast receiver 一般都在等待一個事件的發生,用戶並不希望此類程序被系統強制關閉;進程中 service 的數量必須為 0。存在 service 的進程很有可能在為一個或者多個程序提供某種服務,如 GPS 定位服務。殺死此類進程將使其他進程無法正常服務。

步驟三,再次檢查當前運行的進程,如果 mRemovedProcesses.size() 仍然大於 curMaxProcs,則放寬條件再次進行回收。

步驟四,上面 3 個過程都是針對整個 process 進行的資源回收。在以上過程執行完畢之後,將在更小的粒度上對 Activity 的資源進行回收。與上面所述類似,列表 mLRUActivities 存儲了當前所有運行中的 Activity,排序規則同樣為最少訪問原則。mLRUActivities.size() 返回系統中運行的 Activity 的數量,當其大於 MAX_ACTIVITIES(MAX_ACTIVITIES 是一個常量,一般值為 20,代表系統中最大允許同時存在的 Activity)時。將回收部分滿足條件的 Activity 以減少內存的使用。 這裡回收的只是 Activity 的內存資源,並不會殺死進程,也不會影響進程的運行。當進程需要調用被殺掉的 Activity 時,可以從保存的狀態中回復,當然可能需要相對長一點的時延。

Linux 內核中的內存回收

lowmemorykiller

trimApplications() 函數中會執行一個叫做 updateOomAdjLocked() 的函數,如果返回 false,則執行默認回收,若返回 true 則不執行默認內存回收。
updateOomAdjLocked 將針對每一個進程更新一個名為 adj 的變量,並將其告知 Linux 內核,內核維護一個包含 adj 的數據結構(即進程表),並通過 lowmemorykiller 檢查系統內存的使用情況,在內存不足的情況下殺死一些進程並釋放內存。

由於 Android 操作系統中的所有應用程序都運行在獨立的 Dalvik 虛擬機環境中,Linux 內核無法獲知每個進程的運行狀態,也就無法為每個進程維護一個合適的 adj 值,因此,Android Application Framework 中必須提供一套機制以動態的更新每個進程的 adj。這就是 updateOomAdjLocked()。

Android 基於進程中運行的組件及其狀態規定了默認的五個回收優先級

IMPORTANCE_FOREGROUND:
IMPORTANCE_VISIBLE:
IMPORTANCE_SERVICE:
IMPORTANCE_BACKGROUND:
IMPORTANCE_EMPTY:

  1. 上一頁:
  2. 下一頁:
熱門文章
閱讀排行版
Copyright © Android教程網 All Rights Reserved