我們都知道Android手機上是可以安裝很多App的,每一個App至少是會有一個進程的。創(chuàng)建進程是件麻煩而且耗資源的事情,Android為了讓App啟動的時候能更快,會把那么暫時不使用的App的進程緩存起來,但是內(nèi)存是有限的啊,總不能讓所有的進程都放在內(nèi)存里邊吧,所以Android有一個淘汰機制,會根據(jù)App的運行狀態(tài)設(shè)置一個進程的優(yōu)先級(oom_adj),然后根據(jù)內(nèi)存的緊張程度,把那些優(yōu)先級低(oom_adj值大)的進程kill掉,以保證其他的進程能夠有足夠的內(nèi)存使用。
進程
- Zygote進程
這個是Android框架的主要進程,所有的App進程以及系統(tǒng)服務(wù)進程SystemServer都是由Zygote進程Fork出來的 - App的主進程
每一個App的運行都是在一個獨立的進程,進程的名字就是App的packagename,這些進程都是從Zygote進程Fork出來的,并受AMS(ActivityManagerService)管理 - App的輔助進程
可以允許App有多個進程,在AndroidManifest.xml里邊配置android:process屬性,就可以開啟多進程,這些進程名字都是packagename:name這種,以區(qū)分是屬于哪個App,我一般稱之為輔助進程。但這些進程也都跟主進程一樣,也是從Zygote進程Fork出來的,并受AMS管理 - Native進程
Android除了使用Java,還有NDK,可以使用C/C++去開發(fā),然后這里也是可以Fork出進程的,我一般稱之為Native進程,Native進程可以不受AMS管理,自由度很大,本文暫且不講
優(yōu)先級
App進程的優(yōu)先級是在com.android.server.am.ProcessList
類里邊定義的,這個類在Android的API里邊是找不到的,要想看看里邊的實現(xiàn)可以去Android SDK里邊去找,位于${android-sdk-path}\sources\android-23\com\android\server\am\ProcessList.java
主要有這么幾個優(yōu)先級(oom_adj值):
- UNKNOWN_ADJ = 16
預(yù)留的最低級別,一般對于緩存的進程才有可能設(shè)置成這個級別
Adjustment used in certain places where we don't know it yet. (Generally this is something that is going to be cached, but we don't know the exact value in the cached range to assign yet.)
- CACHED_APP_MAX_ADJ = 15
緩存進程,空進程,在內(nèi)存不足的情況下就會優(yōu)先被kill
This is a process only hosting activities that are not visible, so it can be killed without any disruption.
- CACHED_APP_MIN_ADJ = 9
緩存進程,也就是空進程 - SERVICE_B_ADJ = 8
不活躍的進程
The B list of SERVICE_ADJ -- these are the old and decrepit services that aren't as shiny and interesting as the ones in the A list.
- PREVIOUS_APP_ADJ = 7
切換進程
This is the process of the previous application that the user was in. This process is kept above other things, because it is very common to switch back to the previous app. This is important both for recent task switch (toggling between the two top recent apps) as well as normal UI flow such as clicking on a URI in the e-mail app to view in the browser, and then pressing back to return to e-mail.
- HOME_APP_ADJ = 6
與Home交互的進程
This is a process holding the home application -- we want to try avoiding killing it, even if it would normally be in the background, because the user interacts with it so much.
- SERVICE_ADJ = 5
有Service的進程
This is a process holding an application service -- killing it will not have much of an impact as far as the user is concerned.
- HEAVY_WEIGHT_APP_ADJ = 4
高權(quán)重進程
This is a process with a heavy-weight application. It is in the background, but we want to try to avoid killing it. Value set in system/rootdir/init.rc on startup.
- BACKUP_APP_ADJ = 3
正在備份的進程
This is a process currently hosting a backup operation. Killing it is not entirely fatal but is generally a bad idea.
- PERCEPTIBLE_APP_ADJ = 2
可感知的進程,比如那種播放音樂
This is a process only hosting components that are perceptible to the user, and we really want to avoid killing them, but they are not immediately visible. An example is background music playback.
- VISIBLE_APP_ADJ = 1
可見進程
This is a process only hosting activities that are visible to the user, so we'd prefer they don't disappear.
- FOREGROUND_APP_ADJ = 0
前臺進程
This is the process running the current foreground app. We'd really rather not kill it!
- PERSISTENT_SERVICE_ADJ = -11
重要進程
This is a process that the system or a persistent process has bound to, and indicated it is important.
- PERSISTENT_PROC_ADJ = -12
核心進程
This is a system persistent process, such as telephony. Definitely don't want to kill it, but doing so is not completely fatal.
- SYSTEM_ADJ = -16
系統(tǒng)進程
The system process runs at the default adjustment.
- NATIVE_ADJ = -17
系統(tǒng)起的Native進程
Special code for native processes that are not being managed by the system (so don't have an oom adj assigned by the system).
在Android-18及以下空進程不叫CACHED_APP_MIN_ADJ ,叫HIDDEN_APP_MIN_ADJ,有這么點不一樣,但是值都一樣。
如何查看App進程優(yōu)先級
對于App進程,因為受AMS管理,都會有一個oom_adj的文件記錄著oom_adj的值,但是對于Native進程,那AMS就管不著了。
//oom_adj的值就是進程的優(yōu)先級,
//查看oom_adj值
cat /proc/${pid}/oom_adj
lowmemorykiller 機制
這個機制是在goldfish層面實現(xiàn)的,如果要想具體了解是怎么選擇殺進程的話,需要去看Android drivers下的lowmemorykiller.c的代碼。
編譯過goldfish的人,應(yīng)該知道它其實就是Linux kernel。因為Android是基于Linux的操作系統(tǒng)嘛,kernel其實也是跟著Linux kernel走的,只不過在里邊需要開發(fā)(或者精簡)一些專門針對Android的東西,lowmemorykiller 就是其中的一部分,是個驅(qū)動。至于為啥會被放在drivers/staging
目錄下,可以參考下這篇文章《小議Linux staging tree》
有這么幾個關(guān)鍵點:
- 向系統(tǒng)注冊lowmem_shrinker回調(diào),當(dāng)系統(tǒng)空閑內(nèi)存不足時調(diào)用,去殺進程
- 把空閑內(nèi)存低于多少,就去殺那個級別的進程,我稱之為策略
- 殺的策略由application層根據(jù)內(nèi)存狀況指定,寫入文件傳遞給驅(qū)動
- 根據(jù)策略會計算出min_score_adj
- 每個App進程都有oom_adj值,根據(jù)oom_adj值計算出oom_score_adj(得分值),oom_adj越大,oom_score_adj越高,高于min_score_adj的被列入死亡名單
- 在死亡名單里面選一個占內(nèi)存最大的進程kill掉
所以當(dāng)內(nèi)存不足的時候,進程優(yōu)先級低的(oom_adj越大的),占內(nèi)存大的App進程將會被優(yōu)先kill掉。
至于這個策略嘛,各個ROM可能不一致的,根據(jù)內(nèi)存的大小,系統(tǒng)的嚴格程度來制定,但都只能分6個級別。
minfree:列舉6個內(nèi)存閥值。
比如:32768,61440,73728,129024,147456,184320
adj:列舉6個oom_adj的級別。
比如:0,1,2,3,9,15
這兩個值相互對應(yīng),空閑內(nèi)存低于多少的時候就kill那個級別的進程。
當(dāng)然有些ROM也會把這個參數(shù)定義在init.rc里邊,開機后再寫入minfree和adj文件,傳遞給驅(qū)動
trimApplications機制
僅僅只有低內(nèi)存的情況下才去kill進程嗎?很明顯不是,對于App的運行是有很多狀況的,比如Crash、App退出、系統(tǒng)清理、卸載。
trimApplications是一個方法,定義在ActivityManagerService里邊,Android API里邊也是沒有這個類的,得去SDK里邊找,位于${android-sdk-path}\sources\android-23\com\android\server\am\ActivityManagerService.java
這個機制大概也有幾個關(guān)鍵點:
- package已被卸載的無用進程會被Kill
- persistent的App會被優(yōu)先照顧,進程優(yōu)先級設(shè)置為PERSISTENT_PROC_ADJ=-12
- Activity僅在主進程跑的App會被認為是高權(quán)重進程,HEAVY_WEIGHT_APP_ADJ=4
- 只有前臺進程才是FOREGROUND_APP_ADJ=0,前臺進程不會被殺
- 每當(dāng)Activity、Service等生命周期發(fā)生變化的時候都會引起進程的oo_adj的調(diào)整
- 進程里邊沒有任何的Activity的存在優(yōu)先被殺
- 空進程最容易被殺
如何提高后臺App進程的優(yōu)先級
其實Android框架的思想是很好的,對于空的進程,沒事干的進程直接kill掉,對于用戶體驗來講是不會有影響的,但是往往我們的App都會有推送這個功能,恰巧GCM(Google Cloud Messaging)在國內(nèi)又不能用,所以很多情況下我們也會希望App在后臺的時候也盡量不要被殺。
可以考慮把后臺App進程的優(yōu)先級提高,下面有幾個方法:
- AndroidManifest.xml中配置persistent屬性
<application android:name="App"
android:persistent="true"
android:label="@string/dialerIconLabel"
android:icon="@drawable/ic_launcher_phone">
- 重載back按鍵事件,讓activity在后臺運行,不要Destory
- 開Service,并設(shè)置前臺運行方式
- 與NotificationManager交互,讓進程變成可感知進程
- 發(fā)送/接收廣播,別讓自己變成空進程
很明顯這會消耗更多的電量,也有點流氓,有些需求也許本就不該做。