2018-08-08 13:28:27 1540瀏覽
Android是一個(gè)基于Linux實(shí)現(xiàn)的操作系統(tǒng)。但對(duì)于Linux內(nèi)核來(lái)說(shuō),Android也僅僅只是一個(gè)運(yùn)行在內(nèi)核之上的應(yīng)用程序,與其他運(yùn)行在內(nèi)核之上的應(yīng)用程序沒(méi)有任何區(qū)別。所以Android需要一套機(jī)制管理運(yùn)行在Linux進(jìn)程中的APK應(yīng)用程序。很多參加Android培訓(xùn)的同學(xué)也需要知道這個(gè)知識(shí)點(diǎn)。Android內(nèi)存管理包含兩部分,一部分是Framework對(duì)內(nèi)存的管理,一部分是Linux內(nèi)核對(duì)內(nèi)存管理,這兩部分共同決定應(yīng)用程序的生命周期。本文主要闡述Android內(nèi)存管理機(jī)制的實(shí)現(xiàn)原理,以及在應(yīng)用開(kāi)發(fā)中需要注意的一些事項(xiàng),最后文章總結(jié)了如何實(shí)現(xiàn)殺不死進(jìn)程的一種方法。本文分為兩部分閱讀。
Linux進(jìn)程回收
在Android中,大部分應(yīng)用程序都運(yùn)行在一個(gè)獨(dú)立的Linux進(jìn)程中,每個(gè)進(jìn)程都有獨(dú)立的內(nèi)存空間。隨著各種應(yīng)用程序啟動(dòng),系統(tǒng)內(nèi)存不斷下降,為了保證新應(yīng)用能夠運(yùn)行,Android需要一套機(jī)制殺死暫時(shí)閑置的進(jìn)程。
AndroidFramework并不能直接回收內(nèi)存,其管理進(jìn)程的服務(wù)(ActivityManagerService,以下簡(jiǎn)稱AmS)也同應(yīng)用程序一樣運(yùn)行在Java虛擬機(jī)環(huán)境里。Java虛擬機(jī)都運(yùn)行在各自獨(dú)立的內(nèi)存空間,所以ActivityManagerService沒(méi)有辦法感知應(yīng)用程序是否OOM。
Android系統(tǒng)中還運(yùn)行了一個(gè)OOM進(jìn)程。該進(jìn)程啟動(dòng)時(shí)首先會(huì)在Linux內(nèi)核中把自己注冊(cè)為一個(gè)OOMKiller。AmS需要把每一個(gè)應(yīng)用程序的oom_adj值告知OOMKiller,這個(gè)值的范圍在-16到15之間,值越低,說(shuō)明越重要,這個(gè)值類似于Linux中的nice值,只在標(biāo)準(zhǔn)的Linux中,有其自己的OOMKiller。Android中的OOMKiller進(jìn)程僅僅適用于Android應(yīng)用程序。
當(dāng)內(nèi)核的內(nèi)存管理模塊檢測(cè)到系統(tǒng)內(nèi)存不足時(shí)就會(huì)通知OOMKiller,然后OOMKiller根據(jù)AmS所告知的優(yōu)先級(jí)強(qiáng)制退出優(yōu)先級(jí)低的應(yīng)用程序。
應(yīng)用程序在內(nèi)存中的狀態(tài)
Android官方聲稱,Activity退出后,其所在進(jìn)程并不會(huì)被立即殺死,從而在下次啟動(dòng)Activity時(shí),能夠提高啟動(dòng)速度。這些Activity只有在內(nèi)存緊張時(shí)才會(huì)被系統(tǒng)殺死。所以對(duì)于應(yīng)用程序來(lái)說(shuō),關(guān)閉并不意味著釋放內(nèi)存。
Activity在內(nèi)存中的狀態(tài)
系統(tǒng)只有一個(gè)Activity處于與用戶交互的狀態(tài),對(duì)于非交互狀態(tài)的Activity,AmS會(huì)在內(nèi)部暫時(shí)緩存起來(lái)而不是立即殺死,但如果后臺(tái)Activity數(shù)目超過(guò)一定閾值,AmS則會(huì)強(qiáng)制殺死一些優(yōu)先級(jí)低的Activity。以下是Activity在內(nèi)存或者說(shuō)在AmS中的狀態(tài):
AmS會(huì)記錄最近啟動(dòng)的20個(gè)Activity,如果超過(guò)20則舍棄最早記錄的Activity。
AmS會(huì)將所有正在運(yùn)行的Activity保存在一個(gè)列表中,對(duì)于使用back返回的Activity則從列表中清除。
AmS使用Lru算法保存所有最近使用過(guò)的Activity。
AmS使用一個(gè)列表(mStoppingActivities)保存需要停止的Activity,這種情況
發(fā)生在啟動(dòng)一個(gè)Activity時(shí),AmS遵循先啟動(dòng)后停止的策略,將需要停止的Activity保存在此列表中,等AmS閑置下來(lái)后再停止Activity。
AmS使用一個(gè)列表保存處于finish狀態(tài)(onDestory())的Activity,當(dāng)一個(gè)Activity處于finish狀態(tài)時(shí)(onDestory()執(zhí)行后)不會(huì)被立即殺死,而是保存到該列表中直到超過(guò)系統(tǒng)設(shè)定的警戒線才會(huì)回收該列表中的Activity。
應(yīng)用進(jìn)程在內(nèi)存中的狀態(tài)
每個(gè)應(yīng)用程序都對(duì)應(yīng)著一個(gè)ActivityThread類,該類初始化后就進(jìn)入Looper.loop()函數(shù)中無(wú)限循環(huán)。
Looper.prepareMainLooper();
...
ActivityThreadthread=newActivityThread();
thread.attach(false);
...
Looper.loop();
以后則依靠消息機(jī)制運(yùn)行,既當(dāng)有消息時(shí)處理消息,沒(méi)有消息則應(yīng)用進(jìn)程進(jìn)入sleep狀態(tài)。loop()方法內(nèi)部代碼如下所示:
publicstaticfinalloop(){
Looperme=myLooper();
MessageQueuequeue=me.mQueue;while(true){
Messagemsg=queue.next();//mightblock
...
}
}
在Linux內(nèi)核調(diào)度中,如果一個(gè)線程的狀態(tài)為sleep,則除了占用調(diào)度本身的時(shí)間,不會(huì)占用CPU時(shí)間片。
有三種情況會(huì)喚醒應(yīng)用線程,一種是定時(shí)器中斷(比如我們?cè)O(shè)置的鬧鐘,在程序中可以設(shè)置定時(shí)任務(wù)),第二種是用戶按鍵消息,第三種是Binder消息(Binder用于進(jìn)程間通信,其在應(yīng)用程序中會(huì)自動(dòng)創(chuàng)建一個(gè)線程,Binder在接收到消息后會(huì)想U(xiǎn)I主線程發(fā)送一個(gè)消息從而使queue.next()繼續(xù)執(zhí)行)這就是所謂的消息驅(qū)動(dòng)模式。
所以設(shè)計(jì)良好的應(yīng)用程序當(dāng)處于后臺(tái)時(shí)不會(huì)占用任何CPU時(shí)間,更不會(huì)拖慢系統(tǒng)運(yùn)行速度。其所占用的僅僅是內(nèi)存,即使釋放所占用的內(nèi)存也不會(huì)提高系統(tǒng)運(yùn)行速度。當(dāng)然這里說(shuō)的是設(shè)計(jì)良好的應(yīng)用程序,目前國(guó)內(nèi)很多應(yīng)用在處于后臺(tái)狀態(tài)時(shí)依然會(huì)偷偷干很多事情,這無(wú)疑就拖慢了系統(tǒng)運(yùn)行速度。
Android內(nèi)存回收
Activity所占內(nèi)存在一般情況下不會(huì)被回收,只有在系統(tǒng)內(nèi)存不夠用時(shí)才會(huì)回收,并且回收會(huì)遵循一定規(guī)則。大致可以概括為前臺(tái)Activity最后回收,其次是包含前臺(tái)的Service或者Provider,再其次是后臺(tái)Activity,最后是空進(jìn)程。
內(nèi)存釋放的三個(gè)地方
第一個(gè)是在ActivityManagerService中運(yùn)行,即Android所聲稱的當(dāng)系統(tǒng)內(nèi)存低時(shí),優(yōu)先釋放沒(méi)有任何Activity的進(jìn)程,然后釋放非前臺(tái)Activity對(duì)應(yīng)的進(jìn)程。
第二個(gè)是在OOMKiller中,此時(shí)AmS只要告訴OOM各個(gè)應(yīng)用的優(yōu)先級(jí),然后OOM就會(huì)調(diào)用Linux內(nèi)部的進(jìn)程管理方法殺死優(yōu)先級(jí)較低的進(jìn)程。
第三個(gè)是在應(yīng)用進(jìn)程本身之中,當(dāng)AmS認(rèn)為目標(biāo)進(jìn)程需要被殺死時(shí),首先會(huì)通知目標(biāo)進(jìn)程進(jìn)程內(nèi)存釋放。這包括調(diào)用目標(biāo)進(jìn)程的scheduleLowMemory()方法和processInBackground()方法。
關(guān)閉Activity的三種情況
第一種,從調(diào)用startActivity()開(kāi)始,一般情況下,當(dāng)前都有正在運(yùn)行的Activity,所以需要先暫停當(dāng)前的Activity,而暫停完畢后,AmS會(huì)收到一個(gè)Binder消息,并開(kāi)始從completePaused()處執(zhí)行。在該函數(shù)中,由于上一個(gè)Activity并沒(méi)有finishing,僅僅是stop,所以這里會(huì)把上一個(gè)Activity添加到mStoppingActivity列表中。當(dāng)目標(biāo)Activity啟動(dòng)后,會(huì)向Ams發(fā)送一個(gè)請(qǐng)求進(jìn)行內(nèi)存回收的消息,這會(huì)導(dǎo)致AmS在內(nèi)部調(diào)用activityIdleInternal()方法,該方法中首先會(huì)處理mStoppingActivities列表中的Activity,這就會(huì)調(diào)用stopActivityLocked()方法。這又會(huì)通過(guò)IPC調(diào)用,通知應(yīng)用進(jìn)程stop指定的Activity,當(dāng)stop完畢后,再報(bào)告給AmS,于是AmS再?gòu)腶ctivityStopped()出開(kāi)始執(zhí)行,而這會(huì)調(diào)用trimApplication()方法,該方法會(huì)執(zhí)行內(nèi)存相關(guān)的操作。
第二種,當(dāng)按Back鍵后,會(huì)調(diào)用finishActivityLocked(),然后把該Activity的finishing標(biāo)識(shí)設(shè)為true,然后再調(diào)用startPausingLocked(),當(dāng)目標(biāo)Activity完成暫停后,就會(huì)報(bào)告AmS,此時(shí)AmS又會(huì)從completePaused()處開(kāi)始執(zhí)行。與第一種情況不同,由于此時(shí)暫停的Activity的finishing狀態(tài)已經(jīng)設(shè)置為true,所以會(huì)執(zhí)行finishingActivityLocked(),而不是像第一種情況中僅僅把該Activity添加到mStoppingActivities列表。
第三種,當(dāng)Activity啟動(dòng)后,會(huì)向AmS發(fā)送一個(gè)Idle消息,這會(huì)導(dǎo)致AmS開(kāi)始執(zhí)行activityIdleInternal()方法。該方法會(huì)首先處理mStoppingActivities列表中的對(duì)象,接著處理mFinishingActivities列表,最后再調(diào)用trimApplication()方法。
以上就是關(guān)閉Activity的三種情況,包括stop和destory,客戶進(jìn)程中與之對(duì)應(yīng)的就是onStop()和onDestory()的調(diào)用。
如果使用OOM還有AmS機(jī)制殺死后臺(tái)進(jìn)程后,此時(shí)運(yùn)行的Activity數(shù)量依然超過(guò)MAX_ACTIVITIES(20),則需要繼續(xù)銷毀滿足以下三個(gè)條件的Activity:
Activity必須已經(jīng)stop,但卻沒(méi)有finishing
必須是不可見(jiàn)的,既該Activity窗口上面有其他全屏的窗口,如果不是全屏,則后面的Activity是可見(jiàn)的。
不能是persistent類型,既常駐進(jìn)程不能被殺死。
以上這篇就是小編分享給大家的全部?jī)?nèi)容了,希望能給大家一個(gè)參考,也希望大家多多支持扣丁學(xué)堂,想要了解更多詳情請(qǐng)登錄扣丁學(xué)堂官網(wǎng)咨詢或者關(guān)注微信公眾號(hào),里面有最新的扣丁學(xué)堂
Android視頻教程等你來(lái)看!
【關(guān)注微信公眾號(hào)獲取更多學(xué)習(xí)資料】
查看更多關(guān)于“Android開(kāi)發(fā)技術(shù)”的相關(guān)資訊>>