在大多數(shù)情況下初狰,每個(gè)Android應(yīng)用程序都在自己的Linux進(jìn)程中運(yùn)行互例。當(dāng)需要運(yùn)行某些代碼時(shí),將為應(yīng)用程序創(chuàng)建此過(guò)程媳叨,并且該過(guò)程將一直運(yùn)行,直到不再需要它為止武福,并且系統(tǒng)需要回收其內(nèi)存以供其他應(yīng)用程序使用扩然。
Android的一個(gè)不尋常的基本特征是應(yīng)用程序進(jìn)程的生命周期不是由應(yīng)用程序本身直接控制的。相反界睁,它由系統(tǒng)通過(guò)系統(tǒng)知道正在運(yùn)行的應(yīng)用程序部分的組合,這些事物對(duì)用戶的重要性以及系統(tǒng)中可用的總體內(nèi)存量來(lái)確定翻斟。
應(yīng)用程序開(kāi)發(fā)人員必須了解不同的應(yīng)用程序組件(特別是Activity,Service和BroadcastReceiver)如何影響應(yīng)用程序進(jìn)程的生命周期嘹履。不正確使用這些組件會(huì)導(dǎo)致系統(tǒng)在執(zhí)行重要工作時(shí)終止應(yīng)用程序的進(jìn)程债热。
進(jìn)程生命周期錯(cuò)誤的一個(gè)常見(jiàn)示例是BroadcastReceiver,它在BroadcastReceiver.onReceive()方法中接收Intent時(shí)啟動(dòng)一個(gè)線程焕刮,然后從該函數(shù)返回墙杯。一旦返回,系統(tǒng)會(huì)認(rèn)為BroadcastReceiver不再處于活動(dòng)狀態(tài)高镐,因此不再需要其托管進(jìn)程(除非其他應(yīng)用程序組件處于活動(dòng)狀態(tài))。因此观腊,系統(tǒng)可能隨時(shí)終止進(jìn)程以回收內(nèi)存岩喷,并且這樣做會(huì)終止在進(jìn)程中運(yùn)行的生成的線程。此問(wèn)題的解決方案通常是從BroadcastReceiver安排JobService婶溯,以便系統(tǒng)知道在該過(guò)程中仍有活動(dòng)的工作偷霉。
為了確定在內(nèi)存不足時(shí)應(yīng)該殺死哪些進(jìn)程,Android會(huì)根據(jù)其中運(yùn)行的組件以及這些組件的狀態(tài)將每個(gè)進(jìn)程置于“重要性層次結(jié)構(gòu)”中类少。 這些流程類型(按重要性排序):
1、前臺(tái)進(jìn)程是用戶當(dāng)前正在執(zhí)行的操作所必需的進(jìn)程信轿。
各種應(yīng)用程序組件可以使其包含進(jìn)程以不同方式被視為前景。 如果滿足以下任何條件倘核,則認(rèn)為進(jìn)程處于前臺(tái):
- 它在用戶正在與之交互的屏幕頂部運(yùn)行一個(gè)Activity(已調(diào)用其onResume()方法)即彪。
- 它有一個(gè)當(dāng)前正在運(yùn)行的BroadcastReceiver(它的BroadcastReceiver.onReceive()方法正在執(zhí)行)。
- 它有一個(gè)服務(wù)隶校,當(dāng)前正在其一個(gè)回調(diào)中執(zhí)行代碼(Service.onCreate(),Service.onStart()或Service.onDestroy())绰疤。
在系統(tǒng)中只會(huì)有一些這樣的過(guò)程舞终,如果內(nèi)存太低甚至這些過(guò)程都不能繼續(xù)運(yùn)行,這些過(guò)程只會(huì)作為最后的手段被殺死。 通常煎谍,此時(shí),設(shè)備已達(dá)到內(nèi)存分頁(yè)狀態(tài)满俗,因此需要此操作以保持用戶界面響應(yīng)作岖。
2、一個(gè)可見(jiàn)的過(guò)程正在進(jìn)行用戶當(dāng)前意識(shí)到的工作痘儡,因此殺死它會(huì)對(duì)用戶體驗(yàn)產(chǎn)生明顯的負(fù)面影響沉删。
在以下條件下,可以看到一個(gè)過(guò)程:
- 它正在運(yùn)行一個(gè)活動(dòng)矾瑰,該活動(dòng)在屏幕上對(duì)用戶可見(jiàn),但不在前臺(tái)(已調(diào)用其onPause()方法)凉夯。 例如,如果前景Activity顯示為允許在其后面看到前一個(gè)Activity的對(duì)話框劲够,則可能會(huì)發(fā)生這種情況。
- 它有一個(gè)作為前臺(tái)服務(wù)運(yùn)行的服務(wù)再沧,通過(guò)Service.startForeground()(它要求系統(tǒng)將服務(wù)視為用戶知道的東西,或者對(duì)它們基本上是可見(jiàn)的)淤堵。
- 它正在托管系統(tǒng)用于用戶知道的特定功能的服務(wù)顷扩,例如動(dòng)態(tài)壁紙,輸入法服務(wù)等扎阶。
在系統(tǒng)中運(yùn)行的這些進(jìn)程的數(shù)量比前臺(tái)進(jìn)程更少婶芭,但仍然是相對(duì)受控的。 這些進(jìn)程被認(rèn)為是非常重要的犀农,除非需要這樣做以保持所有前臺(tái)進(jìn)程運(yùn)行,否則不會(huì)被殺死赁濒。
3孟害、服務(wù)進(jìn)程是一個(gè)持有使用startService()方法啟動(dòng)的服務(wù)的進(jìn)程。
雖然用戶不能直接看到這些進(jìn)程击你,但它們通常是用戶關(guān)心的事情(例如后臺(tái)網(wǎng)絡(luò)數(shù)據(jù)上傳或下載)耘子,因此系統(tǒng)將始終保持這些進(jìn)程運(yùn)行,除非沒(méi)有足夠的內(nèi)存來(lái)保留所有進(jìn)程 前景和可見(jiàn)過(guò)程谷誓。
已經(jīng)運(yùn)行了很長(zhǎng)時(shí)間(例如30分鐘或更長(zhǎng)時(shí)間)的服務(wù)可能會(huì)被降級(jí)捍歪,以允許其進(jìn)程下降到下面描述的緩存LRU列表鸵钝。 這有助于避免出現(xiàn)內(nèi)存泄漏或其他問(wèn)題的長(zhǎng)時(shí)間運(yùn)行服務(wù)占用大量RAM而導(dǎo)致系統(tǒng)無(wú)法有效使用緩存進(jìn)程的情況庐镐。
4、緩存進(jìn)程是當(dāng)前不需要的進(jìn)程必逆,因此當(dāng)其他地方需要內(nèi)存時(shí),系統(tǒng)可以根據(jù)需要自由地終止進(jìn)程粟矿。
在正常運(yùn)行的系統(tǒng)中损拢,這些是內(nèi)存管理中涉及的唯一過(guò)程:運(yùn)行良好的系統(tǒng)將始終具有多個(gè)緩存進(jìn)程(用于在應(yīng)用程序之間進(jìn)行更有效的切換),并根據(jù)需要定期終止最舊的進(jìn)程掏秩。只有在非常關(guān)鍵(且不可染D贰)的情況下,系統(tǒng)才會(huì)到達(dá)所有緩存進(jìn)程被殺死的點(diǎn)胆筒,并且必須開(kāi)始終止服務(wù)進(jìn)程。
這些進(jìn)程通常包含一個(gè)或多個(gè)當(dāng)前對(duì)用戶不可見(jiàn)的Activity實(shí)例(已調(diào)用并返回onStop()方法)。如果他們正確地實(shí)現(xiàn)了他們的活動(dòng)生命周期(請(qǐng)參閱活動(dòng)以獲取更多詳細(xì)信息)派桩,當(dāng)系統(tǒng)終止此類流程時(shí)蚌斩,它不會(huì)影響用戶返回該應(yīng)用程序時(shí)的體驗(yàn):它可以在重新創(chuàng)建關(guān)聯(lián)活動(dòng)時(shí)恢復(fù)以前保存的狀態(tài)一個(gè)新的過(guò)程。
這些進(jìn)程保存在偽LRU列表中员魏,列表中的最后一個(gè)進(jìn)程是第一個(gè)被回收內(nèi)存的進(jìn)程叠聋。在此列表上排序的確切策略是平臺(tái)的實(shí)現(xiàn)細(xì)節(jié),但通常它會(huì)嘗試在其他類型的進(jìn)程之前保留更多有用的進(jìn)程(一個(gè)托管用戶的主應(yīng)用程序碌补,他們看到的最后一個(gè)活動(dòng)等)棉饶。還可以應(yīng)用其他用于終止進(jìn)程的策略:對(duì)允許的進(jìn)程數(shù)量的硬限制照藻,對(duì)進(jìn)程可以持續(xù)緩存的時(shí)間量的限制等汗侵。
在決定如何對(duì)流程進(jìn)行分類時(shí),系統(tǒng)將根據(jù)流程中當(dāng)前活動(dòng)的所有組件中最重要的級(jí)別做出決策晰韵。 有關(guān)每個(gè)組件如何對(duì)流程的整個(gè)生命周期做出貢獻(xiàn)的更多詳細(xì)信息宫屠,請(qǐng)參閱Activity,Service和BroadcastReceiver文檔浪蹂。 每個(gè)類的文檔都更詳細(xì)地描述了它們?nèi)绾斡绊懫鋺?yīng)用程序的整個(gè)生命周期。
還可以基于進(jìn)程對(duì)其具有的其他依賴性來(lái)增加進(jìn)程的優(yōu)先級(jí)古劲。 例如缰猴,如果進(jìn)程A已使用Context.BIND_AUTO_CREATE標(biāo)志綁定到Service,或者正在進(jìn)程B中使用ContentProvider闷堡,則進(jìn)程B的分類將始終至少與進(jìn)程A一樣重要疑故。