本篇文章是基于Android9.0來介紹Android系統(tǒng)關(guān)于進(jìn)程的優(yōu)先級是如何定義和管理的。
概述
1.進(jìn)程
進(jìn)程-Process 是程序的一個運(yùn)行實例。通常會有唯一一個pid與之對應(yīng)。但pid不是絕對唯一的,當(dāng)進(jìn)程死亡后pid會被回收給另外的進(jìn)程使用。在Android世界里,App開發(fā)者很容易認(rèn)為系統(tǒng)的四大組件就是進(jìn)程的載體,實際上,它們不能算是完整的進(jìn)程實例,最多只能算是進(jìn)程的組成部分。由于Android系統(tǒng)框架中,系統(tǒng)對進(jìn)程的創(chuàng)建和管理進(jìn)行了封裝,每當(dāng)我們在啟動四大組件Activity, BroadcastReceiver,ContentProvider,Service任意一個的時候,系統(tǒng)就會去檢查該組件所在的進(jìn)程是否已經(jīng)存在,如果不存在,框架就會自動調(diào)用startProcessLocked函數(shù)去創(chuàng)建進(jìn)程。當(dāng)然一個app可以存在多個進(jìn)程,多個app也可以運(yùn)行在同一個進(jìn)程下,我們可以通過Android:process來設(shè)置。
2.優(yōu)先級
Android系統(tǒng)框架設(shè)計理念里是希望對用戶很重要的進(jìn)程盡可能的長期存活,以此來提高用戶體驗。我們知道Android app在啟動的時候會去做很多事情,比如系統(tǒng)會檢測該app進(jìn)程是否存在,如果不存在則需要通知zygote進(jìn)程去fork app進(jìn)程,同時完成application信息的初始化工作。此時如果app的進(jìn)程存在,那么就會省略這個步驟,直接快速喚起app。對于app來說也是一樣,通過進(jìn)程保活可以去實現(xiàn)更多的功能,但是如果所有的app不管有用沒用的都存活下來了,系統(tǒng)的資源畢竟是有限的,系統(tǒng)內(nèi)存很快就會枯竭而亡,這時就需要有合理地進(jìn)程回收機(jī)制了。那么究竟該怎么回收進(jìn)程呢?其實系統(tǒng)是根據(jù)各個app四大組件的狀態(tài)來決定進(jìn)程的優(yōu)先級值adj。系統(tǒng)會根據(jù)一定的策略先去回收優(yōu)先級最低的(同時也是adj值最大的),其次再回收優(yōu)先級略低的,依次類推,直到回收了足夠的系統(tǒng)資源,保證系統(tǒng)正常運(yùn)轉(zhuǎn)。
3.adj取值范圍及含義
| ADJ級別 | 取值 | 含義 |
|---|---|---|
| NATIVE_ADJ | -1000 | native進(jìn)程 |
| SYSTEM_ADJ | -900 | 僅指system_server進(jìn)程 |
| PERSISTENT_PROC_ADJ | -800 | 系統(tǒng)persistent進(jìn)程 |
| PERSISTENT_SERVICE_ADJ | -700 | 關(guān)聯(lián)著系統(tǒng)或persistent進(jìn)程 |
| FOREGROUND_APP_ADJ | 0 | 前臺進(jìn)程 |
| VISIBLE_APP_ADJ | 100 | 可見進(jìn)程 |
| PERCEPTIBLE_APP_ADJ | 200 | 可感知進(jìn)程,比如后臺音樂播放 |
| BACKUP_APP_ADJ | 300 | 備份進(jìn)程 |
| HEAVY_WEIGHT_APP_ADJ | 400 | 重量級進(jìn)程 |
| SERVICE_ADJ | 500 | 服務(wù)進(jìn)程 |
| HOME_APP_ADJ | 600 | Home進(jìn)程 |
| PREVIOUS_APP_ADJ | 700 | 上一個進(jìn)程 |
| SERVICE_B_ADJ | 800 | B List中的Service |
| CACHED_APP_MIN_ADJ | 900 | 不可見進(jìn)程的adj最小值 |
| CACHED_APP_MAX_ADJ | 906 | 不可見進(jìn)程的adj最大值 |
從Android 7.0開始,ADJ采用100、200、300;在這之前的版本ADJ采用數(shù)字1、2、3,這樣的調(diào)整可以更進(jìn)一步地細(xì)化進(jìn)程的優(yōu)先級,比如在VISIBLE_APP_ADJ(100)與PERCEPTIBLE_APP_ADJ(200)之間,可以有ADJ=101、102級別的進(jìn)程。
關(guān)于進(jìn)程的優(yōu)先級可以通過如下的命令查看
adb shell
cd /proc/pid/
oom_adj oom_score oom_score_adj
cat oom_adj
0 表示前臺進(jìn)程FOREGROUND_APP_ADJ
Android 7.0之前的版本:
oom_score -- 是該進(jìn)程的最終得分,分?jǐn)?shù)越高,越容易被殺死;
oom_score_adj -- 范圍:[-1000, 1000],是kernel用來配置進(jìn)程優(yōu)先級的。值越低,最終的oom_score越低。
oom_adj -- 范圍:[-16, 15],是給用戶來配置進(jìn)程優(yōu)先級的。為了方便用戶配置,提供了范圍更小的oom_adj參數(shù),數(shù)字越小優(yōu)先級越高,-17表示該進(jìn)程被保護(hù),不被OOMKiller殺死。
kernel會轉(zhuǎn)換并更新該進(jìn)程實際的oom_score_adj值,它們的換算關(guān)系是:
#define OOM_DISABLE (-17)
#define OOM_SCORE_ADJ_MAX 1000
oom_score_adj = (oom_adj * OOM_SCORE_ADJ_MAX) / -OOM_DISABLE;
oom_adj = (oom_score_adj * - OOM_DISABLE) / OOM_SCORE_ADJ_MAX;
Android 7.0之前的版本,oom_score_adj= oom_adj * 1000/17; 而Android 7.0開始,oom_score_adj= oom_adj,不用再經(jīng)過一次轉(zhuǎn)換。
4.LowMemoryKiller
Android的Low Memory Killer基于Linux的OOM(Out Of Memory Killer)機(jī)制,在Linux中,內(nèi)存是以頁面為單位分配的,OOM的策略更多的是用于分配內(nèi)存不足時觸發(fā),將得分最高的進(jìn)程殺掉。而lmk則會每隔一段時間檢查一次,當(dāng)系統(tǒng)剩余可用內(nèi)存較低時,便會觸發(fā)殺進(jìn)程的策略,根據(jù)不同的剩余內(nèi)存檔位來選擇殺不同優(yōu)先級的進(jìn)程,而不是等到OOM時再來殺進(jìn)程,真正OOM時系統(tǒng)可能已經(jīng)處于異常狀態(tài),系統(tǒng)更希望的是未雨綢繆,在內(nèi)存很低時來殺掉一些優(yōu)先級較低的進(jìn)程來保障后續(xù)操作的順利進(jìn)行。這里不詳細(xì)說,接下來會有一篇關(guān)于Low Memory Killer的文章來詳細(xì)介紹。
那么在哪里可以看到各個剩余內(nèi)存檔位呢?可以通過如下方式:
frameworks/base/services/core/java/com/android/server/am/ProcessList.java
// These are the various interesting memory levels that we will give to
// the OOM killer. Note that the OOM killer only supports 6 slots, so we
// can't give it a different value for every possible kind of process.
private final int[] mOomAdj = new int[] {
FOREGROUND_APP_ADJ, VISIBLE_APP_ADJ, PERCEPTIBLE_APP_ADJ,
BACKUP_APP_ADJ, CACHED_APP_MIN_ADJ, CACHED_APP_MAX_ADJ
};
從ProcessList.java中關(guān)于mOomAdj的定義及注釋中我們可以發(fā)現(xiàn),
系統(tǒng)一共定義了6個檔位,
分別對應(yīng)了上表格中列出的幾種進(jìn)程類型。
adb shell
cat /sys/module/lowmemorykiller/parameters/adj
0,100,200,300,900,906
adj值對應(yīng)如下:
FOREGROUND_APP_ADJ(0)
VISIBLE_APP_ADJ(100)
PERCEPTIBLE_APP_ADJ(200)
BACKUP_APP_ADJ(300)
CACHED_APP_MIN_ADJ(900)
CACHED_APP_MAX_ADJ(906)
cat /sys/module/lowmemorykiller/parameters/minfree
18432,23040,27648,32256,85296,120640
由于一個page=4k,對應(yīng)的換算公式是:value*4/1024,換算結(jié)果如下:
72M,90M,108M,126M,144M,180M
剩余內(nèi)存值檔位對應(yīng)如下:
FOREGROUND_APP_ADJ(72M)
VISIBLE_APP_ADJ(90M)
PERCEPTIBLE_APP_ADJ(108M)
BACKUP_APP_ADJ(126M)
CACHED_APP_MIN_ADJ(144M)
CACHED_APP_MAX_ADJ(180M)
進(jìn)程剛啟動時ADJ等于INVALID_ADJ,當(dāng)執(zhí)行完attachApplication(),該該進(jìn)程的curAdj和setAdj不相等,則會觸發(fā)執(zhí)行setOomAdj()將該進(jìn)程的節(jié)點/proc/pid/oom_score_adj寫入oomadj值。舉例:當(dāng)系統(tǒng)剩余空閑內(nèi)存低于某閾值(比如140MB),則從ADJ大于或等于相應(yīng)閾值(比如900)的進(jìn)程中,選擇ADJ值最大的進(jìn)程,如果存在多個ADJ相同的進(jìn)程,則選擇內(nèi)存最大的進(jìn)程。
在updateOomLevels()過程,會根據(jù)手機(jī)屏幕尺寸或內(nèi)存大小來調(diào)整scale,默認(rèn)大多數(shù)手機(jī)內(nèi)存都大于700MB,則scale等于1。對于64位手機(jī),cached進(jìn)程的閾值會更大些。
private void updateOomLevels(int displayWidth, int displayHeight, boolean write) {
// Scale buckets from avail memory: at 300MB we use the lowest values to
// 700MB or more for the top values.
float scaleMem = ((float)(mTotalMemMb-350))/(700-350);
...
// Scale buckets from screen size.
int minSize = 480*800; // 384000
int maxSize = 1280*800; // 1024000 230400 870400 .264
float scaleDisp = ((float)(displayWidth*displayHeight)-minSize)/(maxSize-minSize);
...
float scale = scaleMem > scaleDisp ? scaleMem : scaleDisp;
if (scale < 0) scale = 0;
else if (scale > 1) scale = 1;
...
final boolean is64bit = Build.SUPPORTED_64_BIT_ABIS.length > 0;
for (int i=0; i<mOomAdj.length; i++) {
int low = mOomMinFreeLow[i];
int high = mOomMinFreeHigh[i];
if (is64bit) {
// Increase the high min-free levels for cached processes for 64-bit
if (i == 4) high = (high*3)/2;
else if (i == 5) high = (high*7)/4;
}
mOomMinFree[i] = (int)(low + ((high-low)*scale));
}
}
ADJ詳解
1.ADJ優(yōu)先級小于0的,就是說正常情況下肯定不會被殺死,即使被殺死了也會被重啟的進(jìn)程。
- NATIVE_ADJ(-1000):是由init進(jìn)程fork出來的Native進(jìn)程,并不受system管控
- SYSTEM_ADJ(-900):是指system_server進(jìn)程
- PERSISTENT_PROC_ADJ(-800): 是指在AndroidManifest.xml中申明android:persistent=”true”的系統(tǒng)(即帶有FLAG_SYSTEM標(biāo)記)進(jìn)程,persistent進(jìn)程一般情況并不會被殺,即便被殺或者發(fā)生Crash系統(tǒng)會立即重新拉起該進(jìn)程
- PERSISTENT_SERVICE_ADJ(-700):是由startIsolatedProcess()方式啟動的進(jìn)程,或者是由system_server或者persistent進(jìn)程所綁定(并且?guī)в蠦IND_ABOVE_CLIENT或者BIND_IMPORTANT)的服務(wù)進(jìn)程
2.ADJ優(yōu)先級大于等于0的
-
FOREGROUND_APP_ADJ(0): 正在前臺運(yùn)行的進(jìn)程,是不應(yīng)該被干掉的進(jìn)程
1.正處于resumed狀態(tài)的Activity; app.adjType = "top-activity"
2.正執(zhí)行一個生命周期回調(diào)的Service(比如執(zhí)行onCreate,onStartCommand,onDestroy等); app.adjType = "exec-service";
3.正執(zhí)行onReceive()的BroadcastReceiver; app.adjType = "broadcast";
4.通過startInstrumentation()啟動的進(jìn)程; app.adjType = "instrumentation"
5.當(dāng)客戶端進(jìn)程activity里面調(diào)用bindService()方法時flags帶有BIND_ADJUST_WITH_ACTIVITY參數(shù),并且該activity處于可見狀態(tài),則當(dāng)前服務(wù)進(jìn)程也屬于前臺進(jìn)程; app.adjType = "service";
6.對于provider進(jìn)程,還有以下兩個條件能成為前臺進(jìn)程:- 當(dāng)Provider的客戶端進(jìn)程ADJ<=FOREGROUND_APP_ADJ時,則Provider進(jìn)程ADJ等于FOREGROUND_APP_ADJ; adjType = "provider";
- 當(dāng)Provider有外部進(jìn)程依賴,也就是調(diào)用了getContentProviderExternal()方法,則ADJ至少等于FOREGROUND_APP_ADJ; app.adjType = "ext-provider";
VISIBLE_APP_ADJ(100): 可見進(jìn)程,比如生命周期還沒有執(zhí)行到onstop的activity,有widget組件在桌面的等還是可以被用戶看到的; app.adjType = "vis-activity";
從Android P開始,進(jìn)一步細(xì)化ADJ級別,增加了VISIBLE_APP_LAYER_MAX = PERCEPTIBLE_APP_ADJ - VISIBLE_APP_ADJ - 1=99,是指VISIBLE_APP_ADJ(100)跟PERCEPTIBLE_APP_ADJ(200)之間有99個槽,則可見級別ADJ的取值范圍為[100,199]。 算法會根據(jù)其所在task的mLayerRank來調(diào)整其ADJ,100加上mLayerRank就等于目標(biāo)ADJ,layer越大,則ADJ越小。
關(guān)于TaskRecord的mLayerRank的計算方式是在updateOomAdjLocked()過程調(diào)用ASS的rankTaskLayersIfNeeded()方法PERCEPTIBLE_APP_ADJ(200): 當(dāng)該進(jìn)程存在不可見的Activity,但Activity正處于PAUSING、PAUSED、STOPPING狀態(tài),則為PERCEPTIBLE_APP_ADJ;app.adjType = "pause-activity" or app.adjType = "stop-activity";
滿足以下任一條件的進(jìn)程也屬于可感知進(jìn)程:
1.foregroundServices非空:前臺服務(wù)進(jìn)程,執(zhí)行startForegroundService()方法; app.adjType = "fg-service";
2.app.forcingToImportant非空:執(zhí)行setProcessImportant()方法,比如Toast彈出過程; app.adjType = "force-imp";
3.hasOverlayUi非空:非activity的UI位于屏幕最頂層,比如顯示類型TYPE_APPLICATION_OVERLAY的窗口; app.adjType = "has-overlay-ui";BACKUP_APP_ADJ(300):執(zhí)行bindBackupAgent()過程的進(jìn)程;
1.執(zhí)行bindBackupAgent()過程,設(shè)置mBackupTarget值;
2.執(zhí)行clearPendingBackup()或unbindBackupAgent()過程,置空mBackupTarget值;HEAVY_WEIGHT_APP_ADJ(400): realStartActivityLocked()過程,當(dāng)應(yīng)用的privateFlags標(biāo)識PRIVATE_FLAG_CANT_SAVE_STATE的進(jìn)程;
HEAVY_WEIGHT_APP一般是在后臺運(yùn)行,要避免它被干掉。Value set in system/rootdir/init.rc on startup.SERVICE_ADJ(500):沒有啟動過Activity,并且30分鐘之內(nèi)活躍過的服務(wù)進(jìn)程。startRequested為true,則代表執(zhí)行startService()且沒有stop的進(jìn)程; app.adjType = "started-services";
HOME_APP_ADJ(600):當(dāng)類型為ACTIVITY_TYPE_HOME的應(yīng)用,比如桌面APP
PREVIOUS_APP_ADJ(700):
1.用戶上一個使用的包含UI的進(jìn)程,為了給用戶在兩個APP之間更好的切換體驗,將上一個進(jìn)程ADJ設(shè)置到PREVIOUS_APP_ADJ的檔次。 當(dāng)activityStoppedLocked()過程會更新上一個應(yīng)用。
2.當(dāng)provider進(jìn)程,上一次使用時間不超過20S的情況下,優(yōu)先級不低于PREVIOUS_APP_ADJ。provider進(jìn)程這個是Android 7.0以后新增的邏輯 ,這樣做的好處是在內(nèi)存比較低的情況下避免擁有provider的進(jìn)程出現(xiàn)顛簸,也就是啟動后殺,然后又被拉。SERVICE_B_ADJ(800):進(jìn)程由SERVICE_ADJ(500)降低到SERVICE_B_ADJ(800),有以下兩種情況:
1.A類Service占比過高:當(dāng)A類Service個數(shù) > Service總數(shù)的1/3時,則加入到B類Service。換句話說,B Service的個數(shù)至少是A Service的2倍。
2.內(nèi)存緊張&&A類Service占用內(nèi)存較高:當(dāng)系統(tǒng)內(nèi)存緊張級別(mLastMemoryLevel)高于ADJ_MEM_FACTOR_NORMAL,且該應(yīng)用所占內(nèi)存lastPss大于或等于CACHED_APP_MAX_ADJ級別所對應(yīng)的內(nèi)存閾值的1/3(默認(rèn)值閾值約等于110MB)
內(nèi)存因子ADJ_MEM_FACTOR共有4個級別,當(dāng)前處于哪個內(nèi)存因子級別,取決于當(dāng)前進(jìn)程中cached進(jìn)程和空進(jìn)程的個數(shù)
final int numCachedAndEmpty = numCached + numEmpty;
int memFactor;
if (numCached <= mConstants.CUR_TRIM_CACHED_PROCESSES
&& numEmpty <= mConstants.CUR_TRIM_EMPTY_PROCESSES) {
if (numCachedAndEmpty <= ProcessList.TRIM_CRITICAL_THRESHOLD) {
memFactor = ProcessStats.ADJ_MEM_FACTOR_CRITICAL;
} else if (numCachedAndEmpty <= ProcessList.TRIM_LOW_THRESHOLD) {
memFactor = ProcessStats.ADJ_MEM_FACTOR_LOW;
} else {
memFactor = ProcessStats.ADJ_MEM_FACTOR_MODERATE;
}
} else {
memFactor = ProcessStats.ADJ_MEM_FACTOR_NORMAL;
}
| 內(nèi)存因子 | 取值 | 先決條件 |
|---|---|---|
| ADJ_MEM_FACTOR_CRITICAL | 3 | Cached+Empty<=3 |
| ADJ_MEM_FACTOR_LOW | 2 | Cached+Empty<=5 |
| ADJ_MEM_FACTOR_MODERATE | 1 | Cached<=5 && Empty<=8 |
| ADJ_MEM_FACTOR_NORMAL | 0 | Cached>5或者Empty>8 |
- 最大緩存進(jìn)程個數(shù):CUR_MAX_CACHED_PROCESSES = MAX_CACHED_PROCESSES = 32
- 最大空進(jìn)程個數(shù): CUR_MAX_EMPTY_PROCESSES = MAX_CACHED_PROCESSES/2 = 16
- Trim空進(jìn)程上限:CUR_TRIM_EMPTY_PROCESSES = MAX_CACHED_PROCESSES/4 = 8
- Trim緩存進(jìn)程上限:CUR_TRIM_CACHED_PROCESSES = MAX_CACHED_PROCESSES/6 = 5
注:用于限制empty或cached進(jìn)程的上限為16個,
并且empty超過8個時會清理掉30分鐘沒有活躍的進(jìn)程。 cached和empty主要是區(qū)別是否有Activity
系統(tǒng)會有相應(yīng)的log輸出:
//默認(rèn)cachedProcessLimit=16
if (numCached > cachedProcessLimit) {
app.kill("cached #" + numCached, true);
}
//默認(rèn)CUR_TRIM_EMPTY_PROCESSES=8, 且滿足30min
if (numEmpty > mConstants.CUR_TRIM_EMPTY_PROCESSES
&& app.lastActivityTime < oldTime) {
app.kill("empty for "+ (
(oldTime + ProcessList.MAX_EMPTY_TIME - app.lastActivityTime)
/ 1000) + "s", true);
}
//默認(rèn)cachedProcessLimit=16
if (numEmpty > emptyProcessLimit) {
app.kill("empty #" + numEmpty, true);
}
-
CACHED_APP_MIN_ADJ(900):
緩存進(jìn)程優(yōu)先級從CACHED_APP_MIN_ADJ(900)到 CACHED_APP_MAX_ADJ(906)。
ADJ的轉(zhuǎn)換算法:
cached: 900, 901, 903, 905
empty: 900, 902, 904, 906
cache process
1.foregroundActivities代表當(dāng)前不是前臺(FOREGROUND_APP_ADJ)進(jìn)程,并且存在Activity的進(jìn)程,當(dāng)該Activity窗口不可見,并且不處于PAUSING(正在)、PAUSED(onPause個)、STOPPING的任一狀態(tài)的情況下,則設(shè)置該進(jìn)程為PROCESS_STATE_CACHED_ACTIVITY。
app.adjType = "cch-act";
2.當(dāng)該進(jìn)程Service的客戶端進(jìn)程存在Activity或者是treatLikeActivity的進(jìn)程,其進(jìn)程狀態(tài)都是cached進(jìn)程。
app.adjType = "cch-as-act";
app.adjType = "cch-client-act";
總結(jié)
Android進(jìn)程優(yōu)先級ADJ的每一個ADJ級別往往都有多種場景,使用adjType完美地區(qū)分相同ADJ下的不同場景; 不同ADJ進(jìn)程所對應(yīng)的schedGroup不同,從而分配的CPU資源也不同,schedGroup大體分為TOP(T)、前臺(F)、后臺(B); ADJ跟AMS中的procState有著緊密的聯(lián)系。
adj:通過調(diào)整oom_score_adj來影響進(jìn)程壽命(Lowmemorykiller殺進(jìn)程策略);
schedGroup:影響進(jìn)程的CPU資源調(diào)度與分配;
procState:從進(jìn)程所包含的四大組件運(yùn)行狀態(tài)來評估進(jìn)程狀態(tài),影響framework的內(nèi)存控制策略。比如控制緩存進(jìn)程和空進(jìn)程個數(shù)上限依賴于procState,再比如控制APP執(zhí)行handleLowMemory()的觸發(fā)時機(jī)等。

CPU調(diào)度組:
| 調(diào)度級別 | 縮寫 | 解釋 |
|---|---|---|
| SCHED_GROUP_BACKGROUND(0) | B | 后臺進(jìn)程組 |
| SCHED_GROUP_DEFAULT(1) | F | 前臺進(jìn)程組 |
| SCHED_GROUP_TOP_APP(2) | T | TOP進(jìn)程組 |
| SCHED_GROUP_TOP_APP_BOUND(3) | T | TOP進(jìn)程組 |
- 常說的前臺進(jìn)程與后臺進(jìn)程,其實是從CPU調(diào)度角度來劃分的前臺與后臺;為了讓用戶正在使用的TOP進(jìn)程能分配到更多的CPU資源,從Android 6.0開始新增了TOP進(jìn)程組,CPU調(diào)度優(yōu)先分配給當(dāng)前正在跟用戶交互的APP,提升用戶體驗。
- 上圖adjType=”broadcast”的CPU調(diào)度組的選擇取決于廣播隊列,當(dāng)receiver接收到的廣播來自于前臺廣播隊列則采用前臺進(jìn)程組,當(dāng)receiver接收到的廣播來自于后臺廣播隊列則采用后臺進(jìn)程組。前后臺廣播隊列的CPU資源調(diào)度優(yōu)先級不同,所以前臺廣播超時10秒就會ANR,而后臺廣播超時60秒才會ANR。更少的CPU資源分配就需要更長的時間來完成執(zhí)行,這也就是為何兩個廣播隊列定義了不同的超時閾值。
- 上圖adjType=”exec-service”的CPU調(diào)度組的選擇取決于caller, 當(dāng)發(fā)起bindService或者startService的調(diào)用者caller屬于后臺進(jìn)程組,callerFg=false,則Service的生命周期回調(diào)運(yùn)行在后臺進(jìn)程組,非常少的CPU資源;當(dāng)caller屬于前臺或者TOP進(jìn)程組,則Service的生命周期回調(diào)運(yùn)行在前臺進(jìn)程組,分配較多的CPU資源。
- 上圖adjType=”service”也有機(jī)會選擇TOP組, 前提條件是在bindService的時候帶有BIND_IMPORTANT的flags,用于標(biāo)記該服務(wù)對于客戶端進(jìn)程很重要。
對于app開發(fā)者的建議:
- UI進(jìn)程與Service進(jìn)程一定要分離,因為對于包含activity的service進(jìn)程,一旦進(jìn)入后臺就成為”cch-started-ui-services”類型的cache進(jìn)程(ADJ>=900),隨時可能會被系統(tǒng)回收;而分離后的Service進(jìn)程服務(wù)屬于SERVICE_ADJ(500),被殺的可能性相對較小。尤其是系統(tǒng)允許自啟動的服務(wù)進(jìn)程必須做UI分離,避免消耗系統(tǒng)較大內(nèi)存。
- 只有真正需要用戶可感知的應(yīng)用,才調(diào)用startForegroundService()方法來啟動前臺服務(wù),此時ADJ=PERCEPTIBLE_APP_ADJ(200),常駐內(nèi)存,并且會在通知欄常駐通知提醒用戶,比如音樂播放,地圖導(dǎo)航。切勿為了常駐而濫用前臺服務(wù),這會嚴(yán)重影響用戶體驗。
- 進(jìn)程中的Service工作完成后,務(wù)必主動調(diào)用stopService或stopSelf來停止服務(wù),避免占據(jù)內(nèi)存,浪費系統(tǒng)資源;
- 不要長時間綁定其他進(jìn)程的service或者provider,每次使用完成后應(yīng)立刻釋放,避免其他進(jìn)程常駐于內(nèi)存;
- APP應(yīng)該實現(xiàn)接口onTrimMemory()和onLowMemory(),根據(jù)TrimLevel適當(dāng)?shù)貙⒎潜仨殐?nèi)存在回調(diào)方法中加以釋放。當(dāng)系統(tǒng)內(nèi)存緊張時會回調(diào)該接口,減少系統(tǒng)卡頓與殺進(jìn)程頻次。
- 減少在?;钌匣ㄐ乃?,更應(yīng)該在優(yōu)化內(nèi)存上下功夫,因為在相同ADJ級別的情況下,系統(tǒng)會選擇優(yōu)先殺內(nèi)存占用的進(jìn)程。
參考:
http://gityuan.com/2018/05/19/android-process-adj/
https://blog.csdn.net/kickxxx/article/details/13996565
https://blog.csdn.net/u012602304/article/details/79066000
https://blog.csdn.net/sinat_34606064/article/details/77932268
http://gityuan.com/2016/09/17/android-lowmemorykiller/
