Android系统中的进程管理:内存的回收
本文是Android系統(tǒng)進程管理的第三篇文章。進程管理的前面兩篇文章,請參見這里:
- Android系統(tǒng)中的進程管理:進程的創(chuàng)建
- Android系統(tǒng)中的進程管理:進程的優(yōu)先級
本文適合Android平臺的應(yīng)用程序開發(fā)者,也適合對于Android系統(tǒng)內(nèi)部實現(xiàn)感興趣的讀者。
前言
內(nèi)存是系統(tǒng)中非常寶貴的資源,即便如今的移動設(shè)備上,內(nèi)存已經(jīng)達到4G甚至6G的級別,但對于內(nèi)存的回收也依然重要,因為在Android系統(tǒng)上,同時運行的進程有可能會有幾十甚至上百個之多。
如何將系統(tǒng)內(nèi)存合理的分配給每個進程,以及如何進行內(nèi)存回收,便是操作系統(tǒng)需要處理的問題之一。
本文會講解Android系統(tǒng)中內(nèi)存回收相關(guān)的知識。
對于內(nèi)存回收,主要可以分為兩個層次:
- 進程內(nèi)的內(nèi)存回收:通過釋放進程中的資源進行內(nèi)存回收
- 進程級的內(nèi)存回收:通過殺死進程來進行內(nèi)存回收
這其中,進程內(nèi)的內(nèi)存回收主要分為兩個方面:
- 虛擬機自身的垃圾回收機制
- 在系統(tǒng)內(nèi)存狀態(tài)發(fā)生變化時,通知應(yīng)用程序,讓開發(fā)者進行內(nèi)存回收
而進程級的內(nèi)存回收主要是依靠系統(tǒng)中的兩個模塊,它們是:
- Linux OOM Killer
- LowMemoryKiller
在特定場景下,他們都會通過殺死進程來進行內(nèi)存回收。
下圖描述了幾種內(nèi)存回收機制:
Android系統(tǒng)的內(nèi)存管理簡介
在Android系統(tǒng)中,進程可以大致分為系統(tǒng)進程和應(yīng)用進程兩大類。
系統(tǒng)進程是系統(tǒng)內(nèi)置的(例如:init,zygote,system_server進程),屬于操作系統(tǒng)必不可少的一部分。系統(tǒng)進程的作用在于:
- 管理硬件設(shè)備
- 提供訪問設(shè)備的基本能力
- 管理應(yīng)用進程
應(yīng)用進程是指應(yīng)用程序運行的進程。這些應(yīng)用程序可能是系統(tǒng)出廠自帶的(例如Launcher,電話,短信等應(yīng)用),也可能是用戶自己安裝的(例如:微信,支付寶等)。
Android中應(yīng)用進程通常都運行在Java虛擬機中。在Android 5.0之前的版本,這個虛擬機是Dalvik,5.0及之后版本,Android引入了新的虛擬機,稱作Android Runtime,簡稱“ART”。
關(guān)于ART和Dalvik可以參見這里:ART and Dalvik。無論是Dalvik還是ART,本身都具有垃圾回收的能力,關(guān)于這一點,我們在后面專門講解。
Android的應(yīng)用程序都會依賴一些公共的資源,例如:Android SDK提供的類和接口,以及Framework公開的圖片,字符串等。為了達到節(jié)省內(nèi)存的目的,這些資源在內(nèi)存中并不是每個應(yīng)用進程單獨一份拷貝。而是會在所有應(yīng)用之間共享,因為所有應(yīng)用進程都是作為Zygote進程fork出來的子進程。關(guān)于這部分內(nèi)容,我們已經(jīng)在Android系統(tǒng)中的進程管理:進程的創(chuàng)建一文中講解過。
在Java語言中,通過new創(chuàng)建的對象都會在堆中分配內(nèi)存。應(yīng)用程序堆的大小是有限的。系統(tǒng)會根據(jù)設(shè)備的物理內(nèi)存大小來確定每個應(yīng)用程序所允許使用的內(nèi)存大小,一旦應(yīng)用程序使用的內(nèi)存超過這個大小,便會發(fā)生OutOfMemoryError。
因此開發(fā)者需要關(guān)心應(yīng)用的內(nèi)存使用狀況。關(guān)于如何監(jiān)測應(yīng)用程序的內(nèi)存使用,可以參見這里:Investigating Your RAM Usage。
開發(fā)者相關(guān)的API
下面是一些與內(nèi)存相關(guān)的開發(fā)者API,它們是Android SDK的一部分。
ComponentCallbacks2
Android系統(tǒng)會根據(jù)當(dāng)前的系統(tǒng)內(nèi)存狀態(tài)和應(yīng)用的自身狀態(tài)對應(yīng)用進行通知。這種通知的目的是希望應(yīng)用能夠感知到系統(tǒng)和自身的狀態(tài)變化,以便開發(fā)者可以更準確的把握應(yīng)用的運行。
例如:在系統(tǒng)內(nèi)存充足時,為了提升響應(yīng)性能,應(yīng)用可以緩存更多的資源。但是當(dāng)系統(tǒng)內(nèi)存緊張時,開發(fā)者應(yīng)當(dāng)釋放一定的資源來緩解內(nèi)存緊張的狀態(tài)。
ComponentCallbacks2接口中的void onTrimMemory(int level)?回調(diào)函數(shù)用來接收這個通知。關(guān)于這一點,在“開發(fā)者的內(nèi)存回收”一節(jié),我們會詳細講解。
ActivityManager
ActivityManager,從名稱中就可以看出,這個類是用來管理Activity的系統(tǒng)服務(wù)。但這個類中也包含了很多運行時狀態(tài)查詢的接口,這其中就包括與內(nèi)存相關(guān)的幾個:
- int getMemoryClass ()?獲取當(dāng)前設(shè)備上,單個應(yīng)用的內(nèi)存大小限制,單位是M。注意,這個函數(shù)的返回值只是一個大致的值。
- void getMemoryInfo (ActivityManager.MemoryInfo outInfo)?獲取系統(tǒng)的內(nèi)存信息,具體結(jié)構(gòu)可以查看ActivityManager.MemoryInfo,開發(fā)者最關(guān)心的可能就是availMem以及totalMem。
- void getMyMemoryState (ActivityManager.RunningAppProcessInfo outState)?獲取調(diào)用進程的內(nèi)存信息
- MemoryInfo[] getProcessMemoryInfo (int[] pids)?通過pid獲取指定進程的內(nèi)存信息
- boolean isLowRamDevice()?查詢當(dāng)前設(shè)備是否是低內(nèi)存設(shè)備
Runtime
Java應(yīng)用程序都會有一個Runtime接口的實例,通過這個實例可以查詢運行時的一些狀態(tài),與內(nèi)存相關(guān)的接口有:
- freeMemory()?獲取Java虛擬機的剩余內(nèi)存
- maxMemory()?獲取Java虛擬機所能使用的最大內(nèi)存
- totalMemory()?獲取Java虛擬機擁有的最大內(nèi)存
虛擬機的垃圾回收
垃圾回收是指:虛擬機會監(jiān)測應(yīng)用程序的對象創(chuàng)建和使用,并在一些特定的時候銷毀無用的對象以回收內(nèi)存。
垃圾回收的基本想法是要找出虛擬機中哪些對象已經(jīng)不會再被使用然后將其釋放。其最常用的算法有下面兩種:
引用計數(shù)算法
引用計數(shù)算法是為每個對象維護一個被引用的次數(shù):對象剛創(chuàng)建時的初始引用計數(shù)為0,每次被一個對象引用時,引用計數(shù)加1,反之減1。當(dāng)一個對象的引用計數(shù)重新回到0時便可以認為是不會被使用的,這些對象便可以被垃圾回收。
讀者可能馬上會想到,當(dāng)有兩個對象互相引用時,這時引用計數(shù)該如何計算。關(guān)于這部分內(nèi)容,這里不再展開講解。有興趣的讀者可以查詢Google或者維基百科:Garbage collection
對象追蹤算法
對象追蹤算法是通過GC root類型的對象為起點,追蹤所有被這些對象所引用的對象,并順著這些被引用的對象繼續(xù)往下追蹤,在追蹤的過程中,對所有被追蹤到的對象打上標記。
而剩下的那些沒有被打過標記的對象便可以認為是沒有被使用的,因此這些對象可以將其釋放。
這里提到的的GC root類型的對象有四類:
- 棧中的local變量,即方法中的局部變量
- 活動的線程(例如主線程或者開發(fā)者創(chuàng)建的線程)
- static變量
- JNI中的引用
下面這幅圖描述了這種算法:
a)表示算法開始時,所有對象的標記為false,然后以GC root為起點開始追蹤和打標記,b)中被追蹤到的對象打上了標記。剩下的沒有打上標記的對象便可以釋放了。算法結(jié)束之后,c)中將所有對象的標記全部置為false。下一輪計算時,重新以GC root開始追蹤。
Dalvik虛擬機主要用的就是垃圾回收算法,這里是其Source:MarkSweep.cpp
開發(fā)者的內(nèi)存回收
內(nèi)存回收并不是僅僅是系統(tǒng)的事情,作為開發(fā)者,也需要在合適的場合下進行內(nèi)存釋放。無節(jié)制的消耗內(nèi)存將導(dǎo)致應(yīng)用程序OutOfMemoryError。
上文中提到,虛擬機的垃圾回收會回收那些不會再被使用到的對象。因此,開發(fā)者所需要做的就是:當(dāng)確定某些對象不會再被使用時,要主動釋放對其引用,這樣虛擬機才能將其回收。對于不再被用到對象,仍然保持對其引用導(dǎo)致其無法釋放,將導(dǎo)致內(nèi)存泄漏的發(fā)生。
為了更好的進行內(nèi)存回收,系統(tǒng)會一些場景下會通知應(yīng)用,希望應(yīng)用能夠配合進行一些內(nèi)存的釋放。
ComponentCallbacks2接口中的?void onTrimMemory(int level)回調(diào)就是用來接收這個事件的。
Activity,?Service,?ContentProvider和Application都實現(xiàn)了這個接口,因此這些類的子類都可以接收這個事件。
onTrimMemory回調(diào)的參數(shù)是一個級別,系統(tǒng)會根據(jù)應(yīng)用本身的狀態(tài)以及系統(tǒng)的內(nèi)存狀態(tài)發(fā)送不同的級別,具體的包括:
- 應(yīng)用處于Runnig狀態(tài)可能收到的級別
- TRIM_MEMORY_RUNNING_MODERATE?表示系統(tǒng)內(nèi)存已經(jīng)稍低
- TRIM_MEMORY_RUNNING_LOW?表示系統(tǒng)內(nèi)存已經(jīng)相當(dāng)?shù)?/li>
- TRIM_MEMORY_RUNNING_CRITICAL?表示系統(tǒng)內(nèi)存已經(jīng)非常低,你的應(yīng)用程序應(yīng)當(dāng)考慮釋放部分資源
- 應(yīng)用的可見性發(fā)生變化時收到的級別
- TRIM_MEMORY_UI_HIDDEN?表示應(yīng)用已經(jīng)處于不可見狀態(tài),可以考慮釋放一些與顯示相關(guān)的資源
- 應(yīng)用處于后臺時可能收到的級別
- TRIM_MEMORY_BACKGROUND?表示系統(tǒng)內(nèi)存稍低,你的應(yīng)用被殺的可能性不大。但可以考慮適當(dāng)釋放資源
- TRIM_MEMORY_MODERATE?表示系統(tǒng)內(nèi)存已經(jīng)較低,當(dāng)內(nèi)存持續(xù)減少,你的應(yīng)用可能會被殺死
- TRIM_MEMORY_COMPLETE?表示系統(tǒng)內(nèi)存已經(jīng)非常低,你的應(yīng)用即將被殺死,請釋放所有可能釋放的資源
這里是這個方法實現(xiàn)的示例代碼:Release memory in response to events
在前面的文章中我們提到過:ActivityManagerService負責(zé)管理所有的應(yīng)用進程。
而這里的通知也是來自ActivityManagerService。在updateOomAdjLocked的時候,ActivityManagerService會根據(jù)系統(tǒng)內(nèi)存以及應(yīng)用的狀態(tài)通過app.thread.scheduleTrimMemory發(fā)送通知給應(yīng)用程序。
這里的app是ProcessRecord,即描述應(yīng)用進程的對象,thread是應(yīng)用的主線程。而scheduleTrimMemory是通過Binder IPC的方式將消息發(fā)送到應(yīng)用進程上。這些內(nèi)容在前面的文章中已經(jīng)介紹過,如果覺得陌生,可以閱讀一下前面兩篇文章。
在ActivityThread中(這個是應(yīng)用程序的主線程),接受到這個通知之后,便會遍歷應(yīng)用進程中所有能接受這個通知的組件,然后逐個回調(diào)通知。
相關(guān)代碼如下:
final void handleTrimMemory(int level) {if (DEBUG_MEMORY_TRIM) Slog.v(TAG, "Trimming memory to level: " + level);ArrayList<ComponentCallbacks2> callbacks = collectComponentCallbacks(true, null);final int N = callbacks.size();for (int i = 0; i < N; i++) {callbacks.get(i).onTrimMemory(level);}WindowManagerGlobal.getInstance().trimMemory(level); }Linux OOM Killer
前面提到的機制都是在進程內(nèi)部通過釋放對象來進行內(nèi)存回收。
而實際上,系統(tǒng)中運行的進程數(shù)量,以及每個進程所消耗的內(nèi)存都是不確定的。
在極端的情況下,系統(tǒng)的內(nèi)存可能處于非常嚴峻的狀態(tài),假設(shè)這個時候所有進程都不愿意釋放內(nèi)存,系統(tǒng)將會卡死。
為了使系統(tǒng)能夠繼續(xù)運轉(zhuǎn)不至于卡死,系統(tǒng)會嘗試殺死一些不重要的進程來進行內(nèi)存回收,這其中涉及的模塊主要是:Linux OOM Killer和LowMemoryKiller。
Linux OOM Killer是Linux內(nèi)核的一部分,其源碼可以在這里查看:/mm/oom_kill.c。
Linux OOM Killer的基本想法是:
當(dāng)系統(tǒng)已經(jīng)沒法再分配內(nèi)存的時候,內(nèi)核會遍歷所有的進程,對每個進程計算badness值,得分(badness)最高的進程將會被殺死。
即:badness得分越低表示進程越重要,反之表示不重要。
Linux OOM Killer的執(zhí)行流程如下:
_alloc_pages -> out_of_memory() -> select_bad_process() -> oom_badness()
這其中,_alloc_pages?是內(nèi)核在分配內(nèi)存時調(diào)用的函數(shù)。當(dāng)內(nèi)核發(fā)現(xiàn)無法再分配內(nèi)存時,便會計算每個進程的badness值,然后選擇最大的(系統(tǒng)認為最不重要的)將其殺死。
那么,內(nèi)核是如何計算進程的badness值的呢?請看下面的代碼:
unsigned long oom_badness(struct task_struct *p, struct mem_cgroup *memcg,const nodemask_t *nodemask, unsigned long totalpages) {long points;long adj;...points = get_mm_rss(p->mm) + p->mm->nr_ptes + get_mm_counter(p->mm, MM_SWAPENTS);task_unlock(p);if (has_capability_noaudit(p, CAP_SYS_ADMIN))points -= (points * 3) / 100;adj *= totalpages / 1000;points += adj;return points > 0 ? points : 1; }從這段代碼中,我們可以看到,影響進程badness值的因素主要有三個:
- 進程的oom_score_adj值
- 進程的內(nèi)存占用大小
- 進程是否是root用戶的進程
即,oom_score_adj(關(guān)于oom_score_adj,在Android系統(tǒng)中的進程管理:進程的優(yōu)先級一文中我們專門講解過。)值越小,進程占用的內(nèi)存越小,并且如果是root用戶的進程,系統(tǒng)就認為這個進程越重要。
反之則被認為越不重要,越容易被殺死。
LowMemoryKiller
OOM Killer是在系統(tǒng)內(nèi)存使用情況非常嚴峻的時候才會起作用。但直到這個時候才開始殺死進程來回收內(nèi)存是有點晚的。因為在進程被殺死之前,其他進程都無法再申請內(nèi)存了。
因此,Google在Android上新增了一個LowMemoryKiller模塊。LowMemoryKiller通常會在Linux OOM Killer工作之前,就開始殺死進程。
LowMemoryKiller的做法是:
提供6個可以設(shè)置的內(nèi)存級別,當(dāng)系統(tǒng)內(nèi)存每低于一個級別時,將oom_score_adj大于某個指定值的進程全部殺死。
這么說會有些抽象,但具體看一下LowMemoryKiller的配置文件我們就好理解了。
LowMemoryKiller在sysfs上暴露了兩個文件來供系統(tǒng)調(diào)整參數(shù),這兩個文件的路徑是:
- /sys/module/lowmemorykiller/parameters/minfree
- /sys/module/lowmemorykiller/parameters/adj
如果你手上有一個Android設(shè)備,你可以通過adb shell連上去之后,通過cat命令查看這兩個文件的內(nèi)容。
這兩個文件是配對使用的,每個文件中都是由逗號分隔的6個整數(shù)值。
在某個設(shè)備上,這兩個文件的值可能分別是下面這樣:
- 18432,23040,27648,32256,55296,80640
- 0,100,200,300,900,906
這組配置的含義是;當(dāng)系統(tǒng)內(nèi)存低于80640k時,將oom_score_adj值大于906的進程全部殺死;當(dāng)系統(tǒng)內(nèi)存低于55296k時,將oom_score_adj值大于900的進程全部殺死,其他類推。
LowMemoryKiller殺死進程的時候會在內(nèi)核留下日志,你可以通過dmesg?命令中看到。這個日志可能是這樣的:
lowmemorykiller: Killing 'gnunet-service-' (service adj 0, to free 327224kB on behalf of 'kswapd0' (21) because cache 6064kB is below limit 6144kB for oom_score_adj 0從這個日志中,我們可以看到被殺死進程的名稱,進程pid和oom_score_adj值。另外還有系統(tǒng)在殺死這個進程之前系統(tǒng)內(nèi)存還剩多少,以及殺死這個進程釋放了多少。
LowMemoryKiller的源碼也在內(nèi)核中,路徑是:kernel/drivers/staging/android/lowmemorykiller.c。
lowmemorykiller.c中定義了如下幾個函數(shù):
- lowmem_shrink
- lowmem_init
- lowmem_exit
- lowmem_oom_adj_to_oom_score_adj
- lowmem_autodetect_oom_adj_values
- lowmem_adj_array_set
- lowmem_adj_array_get
- lowmem_adj_array_free
LowMemoryKiller本身是一個內(nèi)核驅(qū)動程序的形式存在,lowmem_init和lowmem_exit?分別負責(zé)模塊的初始化和退出清理工作。
在lowmem_init函數(shù)中,就是通過register_shrinker向內(nèi)核中注冊了register_shrinker?函數(shù):
static int __init lowmem_init(void) {register_shrinker(&lowmem_shrinker);return 0; }register_shrinker函數(shù)就是LowMemoryKiller的算法核心,這個函數(shù)的代碼和說明如下:
static int lowmem_shrink(struct shrinker *s, struct shrink_control *sc) {struct task_struct *tsk;struct task_struct *selected = NULL;int rem = 0;int tasksize;int i;short min_score_adj = OOM_SCORE_ADJ_MAX + 1;int minfree = 0;int selected_tasksize = 0;short selected_oom_score_adj;int array_size = ARRAY_SIZE(lowmem_adj);int other_free = global_page_state(NR_FREE_PAGES) - totalreserve_pages;int other_file = global_page_state(NR_FILE_PAGES) -global_page_state(NR_SHMEM) -total_swapcache_pages();if (lowmem_adj_size < array_size)array_size = lowmem_adj_size;if (lowmem_minfree_size < array_size)array_size = lowmem_minfree_size;// lowmem_minfree 和lowmem_adj 記錄了兩個配置文件中配置的數(shù)據(jù) for (i = 0; i < array_size; i++) {minfree = lowmem_minfree[i];// 確定當(dāng)前系統(tǒng)處于低內(nèi)存的第幾檔 if (other_free < minfree && other_file < minfree) {// 確定需要殺死的進程的oom_score_adj的上限 min_score_adj = lowmem_adj[i];break;}}if (sc->nr_to_scan > 0)lowmem_print(3, "lowmem_shrink %lu, %x, ofree %d %d, ma %hd\n",sc->nr_to_scan, sc->gfp_mask, other_free,other_file, min_score_adj);rem = global_page_state(NR_ACTIVE_ANON) +global_page_state(NR_ACTIVE_FILE) +global_page_state(NR_INACTIVE_ANON) +global_page_state(NR_INACTIVE_FILE);if (sc->nr_to_scan <= 0 || min_score_adj == OOM_SCORE_ADJ_MAX + 1) {lowmem_print(5, "lowmem_shrink %lu, %x, return %d\n",sc->nr_to_scan, sc->gfp_mask, rem);return rem;}selected_oom_score_adj = min_score_adj;rcu_read_lock();// 遍歷所有進程 for_each_process(tsk) {struct task_struct *p;short oom_score_adj;if (tsk->flags & PF_KTHREAD)continue;p = find_lock_task_mm(tsk);if (!p)continue;if (test_tsk_thread_flag(p, TIF_MEMDIE) &&time_before_eq(jiffies, lowmem_deathpending_timeout)) {task_unlock(p);rcu_read_unlock();return 0;}oom_score_adj = p->signal->oom_score_adj;// 跳過那些oom_score_adj值比目標值小的 if (oom_score_adj < min_score_adj) {task_unlock(p);continue;}tasksize = get_mm_rss(p->mm);task_unlock(p);if (tasksize <= 0)continue;// selected 是將要殺死的備選進程 if (selected) {// 跳過那些oom_score_adj比備選的小的 if (oom_score_adj < selected_oom_score_adj)continue;// 如果oom_score_adj一樣,跳過那些內(nèi)存消耗更小的 if (oom_score_adj == selected_oom_score_adj &&tasksize <= selected_tasksize)continue;}// 更換備選的目標,因為又發(fā)現(xiàn)了一個oom_score_adj更大, // 或者內(nèi)存消耗更大的進程 selected = p;selected_tasksize = tasksize;selected_oom_score_adj = oom_score_adj;lowmem_print(2, "select '%s' (%d), adj %hd, size %d, to kill\n",p->comm, p->pid, oom_score_adj, tasksize);}// 已經(jīng)選中目標,記錄日志并殺死進程 if (selected) {long cache_size = other_file * (long)(PAGE_SIZE / 1024);long cache_limit = minfree * (long)(PAGE_SIZE / 1024);long free = other_free * (long)(PAGE_SIZE / 1024);trace_lowmemory_kill(selected, cache_size, cache_limit, free);lowmem_print(1, "Killing '%s' (%d), adj %hd,\n" \" to free %ldkB on behalf of '%s' (%d) because\n" \" cache %ldkB is below limit %ldkB for oom_score_adj %hd\n" \" Free memory is %ldkB above reserved\n",selected->comm, selected->pid,selected_oom_score_adj,selected_tasksize * (long)(PAGE_SIZE / 1024),current->comm, current->pid,cache_size, cache_limit,min_score_adj,free);lowmem_deathpending_timeout = jiffies + HZ;set_tsk_thread_flag(selected, TIF_MEMDIE);send_sig(SIGKILL, selected, 0);rem -= selected_tasksize;}lowmem_print(4, "lowmem_shrink %lu, %x, return %d\n",sc->nr_to_scan, sc->gfp_mask, rem);rcu_read_unlock();return rem; }進程的死亡處理
在任何時候,應(yīng)用進程都可能死亡,例如被OOM Killer或者LowMemoryKiller殺死,自身crash死亡又或者被用戶手動殺死。無論哪種情況,作為應(yīng)用進程的管理者ActivityManagerService都需要知道。
在應(yīng)用進程死亡之后,ActivityManagerService需要執(zhí)行如下工作:
- 執(zhí)行清理工作?ActivityManagerService內(nèi)部的ProcessRecord以及可能存在的四大組件的相關(guān)結(jié)構(gòu)需要全部清理干凈
- 重新計算進程的優(yōu)先級?上文已經(jīng)提到過,進程的優(yōu)先級是有關(guān)聯(lián)性的,有其中一個進程死亡了,可能會連到影響到其他進程的優(yōu)先級需要調(diào)整。
ActivityManagerService是利用Binder提供的死亡通知機制來進行進程的死亡處理的。關(guān)于Binder請參閱其他資料,限于篇幅關(guān)系,這里不再展開講解。
簡單來說,死亡通知機制就提供了進程間的一種死亡監(jiān)聽的能力:當(dāng)目標進程死亡的時候,監(jiān)聽回調(diào)會執(zhí)行。
ActivityManagerService中的AppDeathRecipient監(jiān)聽了應(yīng)用進程的死亡消息,該類代碼如下:
private final class AppDeathRecipient implements IBinder.DeathRecipient {final ProcessRecord mApp;final int mPid;final IApplicationThread mAppThread;AppDeathRecipient(ProcessRecord app, int pid,IApplicationThread thread) {mApp = app;mPid = pid;mAppThread = thread;}@Overridepublic void binderDied() {synchronized(ActivityManagerService.this) {appDiedLocked(mApp, mPid, mAppThread, true);}} }每一個應(yīng)用進程在啟動之后,都會attach到ActivityManagerService上通知它自己的進程已經(jīng)啟動完成了。這時ActivityManagerService便會為其創(chuàng)建一個死亡通知的監(jiān)聽器。在這之后如果進程死亡了,ActivityManagerService便會收到通知。
private final boolean attachApplicationLocked(IApplicationThread thread,int pid) {...try {AppDeathRecipient adr = new AppDeathRecipient(app, pid, thread);thread.asBinder().linkToDeath(adr, 0);app.deathRecipient = adr;} catch (RemoteException e) {app.resetPackageList(mProcessStats);startProcessLocked(app, "link fail", processName);return false;}... }進程死亡之后的處理工作是appDiedLocked這個方法中處理的,這部分還是比較容易理解的,這里就不過多講解了。
結(jié)束語
這三篇文章,我們詳細講解了Android系統(tǒng)中進程的創(chuàng)建,優(yōu)先級的管理和內(nèi)存回收。這些內(nèi)容對于所有運行在Android系統(tǒng)中的應(yīng)用進程都是適用的。
優(yōu)秀的開發(fā)者應(yīng)該充分了解這些內(nèi)容,因為這是與應(yīng)用的生命周期密切相關(guān)的。
由于篇幅所限,這其中有些知識我們沒有詳細展開討論,但有些內(nèi)容會在今后的文章中專門講解。
由于筆者水平有限,文章中不免有所錯漏,歡迎讀者指出。
參考資料與推薦讀物
Overview of Android Memory Management
Understanding Java Garbage Collection
Processes and Threads
Java Memory Management
Debugging ART Garbage Collection
Android Runtime
Taming the OOM killer
OOM Killer
Out Of Memory Management
原文: http://qiangbo.space/2016-12-08/AndroidAnatomy_Process_Recycle/
總結(jié)
以上是生活随笔為你收集整理的Android系统中的进程管理:内存的回收的全部內(nèi)容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: Android系统中的进程管理:进程的创
- 下一篇: 理解Android Binder机制(1