Android開發(fā)中,令人頭疼的惫埽活問題始終纏繞每一個開發(fā)者其馏。如何保證自己的進程不被系統(tǒng)回收呢?首當其沖應該是保證自己進程的優(yōu)先級爆安。
Android系統(tǒng)在運行時叛复,如果遭遇到內存過低,為保證系統(tǒng)穩(wěn)定與流暢,會回收一部分不常用的進程(當然很多三方rom如miui會在電量過低也會回收)褐奥。這個回收過程當然不是隨意回收咖耘,系統(tǒng)需要有一個判斷進程優(yōu)先級的指標,幫助系統(tǒng)判斷哪些資源是優(yōu)先級高需要保留撬码,哪些資源優(yōu)先級比較低需要釋放該資源儿倒。
ADJ就是系統(tǒng)殺死進程的重要指標
本文從linux\Android進程優(yōu)先級:adj分數(shù),淺析一下如何查看adj以及各個adj分數(shù)背后所代表的含義呜笑。
1.ADJ 如何查看
利用adb shell
1.ps | grep 包名 //查看當前app的進程號
2.cat /proc/進程號/oom_adj //查看當前進程的adj值(早期android和linux使用义桂,現(xiàn)已廢棄,但仍然有效)
3.cat /proc/進程號/oom_score_adj //這個是新版本的查看adj的命令蹈垢,adj有效值為-1000~1000
2.ADJ的值的各種含義
ADJ級別 取值 含義
NATIVE_ADJ -1000 native進程
SYSTEM_ADJ -900 僅指system_server進程
PERSISTENT_PROC_ADJ -800 系統(tǒng)persistent進程
PERSISTENT_SERVICE_ADJ -700 關聯(lián)著系統(tǒng)或persistent進程
FOREGROUND_APP_ADJ 0 前臺進程
VISIBLE_APP_ADJ 100 可見進程
PERCEPTIBLE_APP_ADJ 200 可感知進程慷吊,比如后臺音樂播放
BACKUP_APP_ADJ 300 備份進程
HEAVY_WEIGHT_APP_ADJ 400 重量級進程
SERVICE_ADJ 500 服務進程(A list中的service)
HOME_APP_ADJ 600 Home進程
PREVIOUS_APP_ADJ 700 上一個進程
SERVICE_B_ADJ 800 B List中的Service
CACHED_APP_MIN_ADJ 900 不可見進程的adj最小值
CACHED_APP_MAX_ADJ 906 不可見進程的adj最大值
3.ADJ觸發(fā)順序
ADJ是一種算法,用于系統(tǒng)判斷進程優(yōu)先級以觸發(fā)Linux的LMK(LowMemoryKill)機制曹抬。一般觸發(fā)時機(Linux下)是在系統(tǒng)低內存時溉瓶,為了維護正在運行的進程,殺掉優(yōu)先級比較低(adj值比較高)的其他進程谤民。
在Android中這一機制有所改動堰酿。在ActivityManagerService里有具體的計算Adj值的源碼。
進程剛啟動時ADJ等于INVALID_ADJ张足,當執(zhí)行完attachApplication()触创,該該進程的curAdj和setAdj不相等,則會觸發(fā)執(zhí)行setOomAdj()將該進程的節(jié)點/proc/pid/oom_score_adj寫入oomadj值为牍。下圖參數(shù)為Android原生閾值哼绑,當系統(tǒng)剩余空閑內存低于某閾值(比如147MB),則從ADJ大于或等于相應閾值(比如900)的進程中碉咆,選擇ADJ值最大的進程抖韩,如果存在多個ADJ相同的進程,則選擇內存最大的進程疫铜。 如下是64位機器茂浮,LMK默認閾值圖:
----------ADJ----------------Memory Left------------
FOREGROUND_APP_ADJ(0) 73MB
VISIBLE_APP_ADJ(100) 92MB
PERCEPTIBLE_APP_ADJ(200) 110MB
BACKUP_APP_ADJ(300) 129MB
CACHED_APP_MIN_ADJ(900) 221MB
CACHED_APP_MAX_ADJ(906) 332MB
4.高級進程 ADJ<0的進程
1.NATIVE_ADJ(-1000):是由init進程fork出來的Native進程,并不受system管控壳咕;
2.SYSTEM_ADJ(-900):是指system_server進程席揽;
3.PERSISTENT_PROC_ADJ(-800): 是指在AndroidManifest.xml中申明android:persistent=”true”的系統(tǒng)(即帶有FLAG_SYSTEM標記)進程,persistent進程一般情況并不會被殺谓厘,即便被殺或者發(fā)生Crash系統(tǒng)會立即重新拉起該進程幌羞。
4.PERSISTENT_SERVICE_ADJ(-700):是由startIsolatedProcess()方式啟動的進程,或者是由system_server或者persistent進程所綁定(并且?guī)в蠦IND_ABOVE_CLIENT或者BIND_IMPORTANT)的服務進程
5.總結
Android進程優(yōu)先級ADJ的每一個ADJ級別往往都有多種場景庞呕,使用adjType完美地區(qū)分相同ADJ下的不同場景新翎; 不同ADJ進程所對應的schedGroup不同程帕,從而分配的CPU資源也不同,schedGroup大體分為TOP(T)地啰、前臺(F)愁拭、后臺(B); ADJ跟AMS中的procState有著緊密的聯(lián)系亏吝。
1.adj:通過調整oom_score_adj來影響進程壽命(Lowmemorykiller殺進程策略)岭埠;
2.schedGroup:影響進程的CPU資源調度與分配;
3.procState:從進程所包含的四大組件運行狀態(tài)來評估進程狀態(tài)蔚鸥,影響framework的內存控制策略惜论。比如控制緩存進程和空進程個數(shù)上限依賴于procState,再比如控制APP執(zhí)行handleLowMemory()的觸發(fā)時機等止喷。
為了說明整體關系馆类,以ADJ為中心來講解跟adjType,schedGroup,procState的對應關系,下面以一幅圖來詮釋整個ADJ算法的精髓弹谁,幾乎涵蓋了ADJ算法調整的絕大多數(shù)場景乾巧。
6.最后,開發(fā)時應注意:
1.UI進程與Service進程一定要分離预愤,因為對于包含activity的service進程沟于,一旦進入后臺就成為”cch-started-ui-services”類型的cache進程(ADJ>=900),隨時可能會被系統(tǒng)回收植康;而分離后的Service進程服務屬于SERVICE_ADJ(500)旷太,被殺的可能性相對較小。尤其是系統(tǒng)允許自啟動的服務進程必須做UI分離销睁,避免消耗系統(tǒng)較大內存供璧。
只有真正需要用戶可感知的應用,才調用startForegroundService()方法來啟動前臺服務榄攀,此時ADJ=PERCEPTIBLE_APP_ADJ(200)嗜傅,常駐內存,并且會在通知欄常駐通知提醒用戶檩赢,比如音樂播放,地圖導航违寞。切勿為了常駐而濫用前臺服務贞瞒,這會嚴重影響用戶體驗。
2.進程中的Service工作完成后趁曼,務必主動調用stopService或stopSelf來停止服務军浆,避免占據(jù)內存,浪費系統(tǒng)資源挡闰;
3.不要長時間綁定其他進程的service或者provider乒融,每次使用完成后應立刻釋放掰盘,避免其他進程常駐于內存;
4.APP應該實現(xiàn)接口onTrimMemory()和onLowMemory()赞季,根據(jù)TrimLevel適當?shù)貙⒎潜仨殐却嬖诨卣{方法中加以釋放愧捕。當系統(tǒng)內存緊張時會回調該接口,減少系統(tǒng)卡頓與殺進程頻次申钩。
5.減少在贝位妫活上花心思,更應該在優(yōu)化內存上下功夫撒遣,因為在相同ADJ級別的情況下邮偎,系統(tǒng)會選擇優(yōu)先殺內存占用的進程。
原文:https://blog.csdn.net/zhangbijun1230/article/details/81347749