查看adj
可以通過命令:
adb shell
//篩選進程
ps | grep <包名|pid>
//然後,其中oom_score_adj是內核計算過後的adj
cat proc/<pid>/oom_score_adj
方法2
adb shell
dumpsys activity o
//然後查看
ProcessRecord中下面這些屬性反應了oom_score_adj的值
int maxAdj; // Maximum OOM adjustment for this process
int curRawAdj; // Current OOM unlimited adjustment for this process
int setRawAdj; // Last set OOM unlimited adjustment for this process
int curAdj; // Current OOM adjustment for this process
int setAdj; // Last set OOM adjustment for this process
其中:
- maxAdj 指定了該進程允許的oom_score_adj最大值(主要給系統應用和常駐內存使用,通過maxAdj保證這些進程擁有較高優先級)
- curXXX這一組記錄了這一次優先級計算的結果,會將curXXX複製給對應的setXXX這一組上進行備份。
- xxxRawAdj記錄了沒有經過限制的adj值,“沒有經過限制”是指這其中的值可能是超過了oom_score_adj文件所允許的範圍(-1000 ~ 1000)
- ProcessList.Java中預定義了oom_score_adj的可能取值。
static final int UNKNOWN_ADJ = 1001; // 未知進程
static final int PREVIOUS_APP_ADJ = 700; // 前一個應用
static final int HOME_APP_ADJ = 600; // 桌面進程
static final int SERVICE_ADJ = 500; // 包含了Service的進程
static final int HEAVY_WEIGHT_APP_ADJ = 400; // 重量級進程
static final int BACKUP_APP_ADJ = 300; // 備份應用進程
static final int PERCEPTIBLE_APP_ADJ = 200; // 可感知的進程
static final int VISIBLE_APP_ADJ = 100; // 可見進程
static final int VISIBLE_APP_LAYER_MAX = PERCEPTIBLE_APP_ADJ - VISIBLE_APP_ADJ - 1;
static final int FOREGROUND_APP_ADJ = 0; // 前臺進程
static final int PERSISTENT_SERVICE_ADJ = -700; // 常駐服務進程
static final int PERSISTENT_PROC_ADJ = -800; // 常駐應用進程
static final int SYSTEM_ADJ = -900; // 系統進程
static final int NATIVE_ADJ = -1000; // native系統進程
解釋上面這些可能的情況:
- FOREGROUND_APP_ADJ = 0,這個是前臺應用進程的優先級,正在和用戶交互的進程(普通應用獲得的最高優先級)
- VISIBLE_APP_ADJ是具有可見Activity進程的優先級,前臺的Activity設置透明,或者小窗口後面的Activity也可見這種情況
- PERCEPTIBLE_APP_ADJ是指用戶可感知的進程,可感知的進程包括:
1.進程中包含了處於pause狀態或者正在pause的Activity
2.進程中包含了正在stop的Activity
3.進程中包含了前臺的Service
- PREVIOUS_APP_ADJ描述的是前一個應用的優先級。在啓動新的Activity時,如果新啓動的Activity是屬於一個新的進程的,那麼當前即將被stop的Activity所在的進程便會成爲“前一個應用”進程。
- HEAVY_WEIGHT_APP_ADJ 描述的重量級進程是指那些通過Manifest指明不能保存狀態的應用進程。
- PERSISTENT_SERVICE_ADJ = -700,PERSISTENT_PROC_ADJ = -800,系統中的一些進程,比如System_ADJ,NATIVE_ADJ=-1000
進程分類
- 前臺進程 (Foreground process)
- 包含用戶正在交互的 Activity(已調用 Activity 的 onResume() 方法)
- 包含某個 Service,後者綁定到用戶正在交互的 Activity
- 包含正在“前臺”運行的 Service(已調用 startForeground())
- 包含正執行一個生命週期回調的 Service(onCreate()、onStart() 或 onDestroy())
- 包含正執行其 onReceive() 方法的 BroadcastReceiver
- 可見進程(Visible process)
- 不再前臺,但對前臺有影響,比如如果前臺 Activity 啓動了一個對話框,允許在其後顯示上一 Activity,則有可能會發生這種情況。
- 託管綁定到可見(或前臺)Activity 的 Service
- 服務進程 (Service process)
- 使用startservice()方法啓動服務,服務與可見內容沒直接關聯(下載,播放音樂等)屬於可感知
- 後臺進程 (Background process)
- 不可見的Activity進程(調用onStop()方法)這類進程保存在LRU列表中。
- 空進程 (Empty process)
- 不包含任何活動應用組件的進程。目的是通過應用緩存進程,而不浪費時間在啓動新的進程。
Android中進程管理的機制
platform/frameworks/base/services/core/java/com/android/server/am/ActivityManagerService.java)
platform/frameworks/base/services/core/java/com/android/server/am/ProcessList.java
platform/system/core/lmkd/lmkd.c
kernel/common/drivers/staging/Android/lowmemorykiller.c
通過輸入命令:
adb shell
dumpsys activity o
查看有關進程狀態
Android m
殺進程與階段對應
對應在ProcessList.java
中定義
級別 | 常量名稱 | 內存大小 | 簡述 |
---|---|---|---|
-16 | SYSTEM_ADJ | 61440 kB | 系統進程 |
-12 | PERSISTENT_PROC_ADJ | 61440 kB | 系統persistent進程,比如telephony |
-11 | PERSISTENT_SERVICE_ADJ | 61440 kB | 關聯着系統或persistent進程 |
0 | FOREGROUND_APP_ADJ | 61440 kB | 前臺進程(Foreground process |
1 | VISIBLE_APP_ADJ | 76800 kB | 可見進程(Visible process) |
2 | PERCEPTIBLE_APP_ADJ | 92160 kB | 可感知進程,比如後臺音樂播放 |
3 | BACKUP_APP_ADJ | 107520 kB | 備份進程 |
4 | HEAVY_WEIGHT_APP_ADJ | 137660 kB | 後臺的重量級進程,system/rootdir/init.rc文件中設置 |
5 | SERVICE_ADJ | 137660 kB | 服務進程(Service process) |
6 | HOME_APP_ADJ | 137660 kB | Home進程 |
7 | PREVIOUS_APP_ADJ | 137660 kB | 上一個App的進程(往往通過按返回鍵) |
8 | SERVICE_B_ADJ | 137660 kB | List中的Service(較老的、使用可能性更小) |
9 | CACHED_APP_MIN_ADJ | 137660 kB | 不可見進程的adj最小值 |
15 | CACHED_APP_MAX_ADJ | 174948 kB | 不可見進程的adj最大值 |
Android n
殺進程與階段對應
對應在ProcessList.java
中定義
級別 | 常量名稱 | 內存大小 | lmk殺進程根據adj6檔 |
---|---|---|---|
-900 | SYSTEM_ADJ | 73,728k | |
-800 | PERSISTENT_PROC_ADJ | 73,728K | |
-700 | PERSISTENT_SERVICE_ADJ | 73,728K | |
0 | FOREGROUND_APP_ADJ | 73,728K | + |
100 | VISIBLE_APP_ADJ | 92,160K | + |
200 | PERCEPTIBLE_APP_ADJ | 110,592K | + |
300 | BACKUP_APP_ADJ | 129,024K | + |
400 | HEAVY_WEIGHT_APP_ADJ | 221,184K | |
500 | SERVICE_ADJ | 221,184K | |
600 | HOME_APP_ADJ | 221,184K | |
700 | PREVIOUS_APP_ADJ | 221,184K | |
800 | SERVICE_B_ADJ | 221,184K | |
900 | CACHED_APP_MIN_ADJ | 221,184K | + |
906 | CACHED_APP_MAX_ADJ | 322,560K | + |
Process state(m and n)
對應在ActivityManager中定義一下幾種進程的狀態
state級別 | 取值 | 解釋 | 優先級(大於state)return IMPORTANCE_XXX |
---|---|---|---|
PROCESS_STATE_CACHED_EMPTY | 16 | 進程處於cached狀態,且爲空進程 | 400 |
PROCESS_STATE_CACHED_ACTIVITY_CLIENT | 15 | 進程處於cached狀態,且爲另一個cached進程(內含Activity)的client進程 | 400 |
PROCESS_STATE_CACHED_ACTIVITY | 14 | 進程處於cached狀態,且內含Activity | 400 |
PROCESS_STATE_LAST_ACTIVITY | 13 | 後臺進程,且擁有上一次顯示的Activity | 400 |
PROCESS_STATE_HOME | 12 | 後臺進程,且擁有home Activity | 400 |
PROCESS_STATE_RECEIVER | 11 | 後臺進程,且正在運行receiver | 300 |
PROCESS_STATE_SERVICE | 10 | 後臺進程,且正在運行service | 300 |
PROCESS_STATE_HEAVY_WEIGHT | 9 | 後臺進程,但無法執行restore,因此儘量避免kill該進程 | 170 |
PROCESS_STATE_BACKUP | 8 | 後臺進程,正在運行backup/restore操作 | 130 |
PROCESS_STATE_IMPORTANT_BACKGROUND | 7 | 對用戶很重要的進程,用戶不可感知其存在 | 130 |
PROCESS_STATE_IMPORTANT_FOREGROUND | 6 | 對用戶很重要的進程,用戶可感知其存在 | 200 |
PROCESS_STATE_TOP_SLEEPING | 5 | 與PROCESS_STATE_TOP一樣,但此時設備正處於休眠狀態 | 150 |
PROCESS_STATE_FOREGROUND_SERVICE | 4 | 擁有給一個前臺Service | 125 |
PROCESS_STATE_BOUND_FOREGROUND_SERVICE | 3 | 擁有給一個前臺Service,且由系統綁定 | 100 |
PROCESS_STATE_TOP | 2 | 擁有當前用戶可見的top Activity | 100 |
PROCESS_STATE_PERSISTENT_UI | 1 | persistent系統進程,並正在執行UI操作 | 100 |
PROCESS_STATE_PERSISTENT | 0 | persistent系統進程 | 100 |
PROCESS_STATE_NONEXISTENT | -1 | 不存在的進程 | 1000 |
進程優先級定義
在 ActivityManager 中的 RunningAppProcessInfo 類中定義了進程的優先級 IMPORTANCE 值
/**
* Constant for {@link #importance}: This process is running the
* foreground UI; that is, it is the thing currently at the top of the screen
* that the user is interacting with.
*/
public static final int IMPORTANCE_FOREGROUND = 100;
/**
* Constant for {@link #importance}: This process is running a foreground
* service, for example to perform music playback even while the user is
* not immediately in the app. This generally indicates that the process
* is doing something the user actively cares about.
*/
public static final int IMPORTANCE_FOREGROUND_SERVICE = 125;
/**
* Constant for {@link #importance}: This process is running the foreground
* UI, but the device is asleep so it is not visible to the user. This means
* the user is not really aware of the process, because they can not see or
* interact with it, but it is quite important because it what they expect to
* return to once unlocking the device.
*/
public static final int IMPORTANCE_TOP_SLEEPING = 150;
/**
* Constant for {@link #importance}: This process is running something
* that is actively visible to the user, though not in the immediate
* foreground. This may be running a window that is behind the current
* foreground (so paused and with its state saved, not interacting with
* the user, but visible to them to some degree); it may also be running
* other services under the system's control that it inconsiders important.
*/
public static final int IMPORTANCE_VISIBLE = 200;
/**
* Constant for {@link #importance}: This process is not something the user
* is directly aware of, but is otherwise perceptable to them to some degree.
*/
public static final int IMPORTANCE_PERCEPTIBLE = 130;
/**
* Constant for {@link #importance}: This process is running an
* application that can not save its state, and thus can't be killed
* while in the background.
* @hide
*/
public static final int IMPORTANCE_CANT_SAVE_STATE = 170;
/**
* Constant for {@link #importance}: This process is contains services
* that should remain running. These are background services apps have
* started, not something the user is aware of, so they may be killed by
* the system relatively freely (though it is generally desired that they
* stay running as long as they want to).
*/
public static final int IMPORTANCE_SERVICE = 300;
/**
* Constant for {@link #importance}: This process process contains
* background code that is expendable.
*/
public static final int IMPORTANCE_BACKGROUND = 400;
/**
* Constant for {@link #importance}: This process is empty of any
* actively running code.
*/
public static final int IMPORTANCE_EMPTY = 500;
/**
* Constant for {@link #importance}: This process does not exist.
*/
public static final int IMPORTANCE_GONE = 1000;
/** @hide */
public static int procStateToImportance(int procState) {
if (procState == PROCESS_STATE_NONEXISTENT) {
return IMPORTANCE_GONE;
} else if (procState >= PROCESS_STATE_HOME) {
return IMPORTANCE_BACKGROUND;
} else if (procState >= PROCESS_STATE_SERVICE) {
return IMPORTANCE_SERVICE;
} else if (procState > PROCESS_STATE_HEAVY_WEIGHT) {
return IMPORTANCE_CANT_SAVE_STATE;
} else if (procState >= PROCESS_STATE_IMPORTANT_BACKGROUND) {
return IMPORTANCE_PERCEPTIBLE;
} else if (procState >= PROCESS_STATE_IMPORTANT_FOREGROUND) {
return IMPORTANCE_VISIBLE;
} else if (procState >= PROCESS_STATE_TOP_SLEEPING) {
return IMPORTANCE_TOP_SLEEPING;
} else if (procState >= PROCESS_STATE_FOREGROUND_SERVICE) {
return IMPORTANCE_FOREGROUND_SERVICE;
} else {
return IMPORTANCE_FOREGROUND;
}
}
根據上面代碼可知進程的優先級和進程的狀態掛鉤,每一個狀態對應一種優先級。
AMS中有三個核心方法
- updateOomAdjLocked:更新adj,當目標進程爲空,或者被殺則返回false;否則返回true;
- computeOomAdjLocked:計算adj,返回計算後RawAdj值;
- applyOomAdjLocked:應用adj,當需要殺掉目標進程則返回false;否則返回true。
updateOomAdjLocked 中會調用 computeOomAdjLocked 和 applyOomAdjLocked。
LowMemoryKiller 的閾值的設定
閾值的設定
- /sys/module/lowmemorykiller/parameters/adj
- /sys/module/lowmemorykiller/parameters/minfree
shamu:/ # cat /sys/module/lowmemorykiller/parameters/adj
0,100,200,300,900,906
shamu:/ # cat /sys/module/lowmemorykiller/parameters/minfree
18432,23040,27648,32256,36864,46080
minfree中數值的單位是內存中的頁面數量,一般情況下一個頁面是4KB。
例如:將1,6寫入節點/sys/module/lowmemorykiller/parameters/adj,將1024,8192寫入節點/sys/module/lowmemorykiller/parameters/minfree。
策略:當系統可用內存低於8192個pages時,則會殺掉oom_score_adj>=6的進程;當系統可用內存低於1024個pages時,則會殺掉oom_score_adj>=1的進程。
lmkd 守護進程
system/core/lmkd/lmkd.c
lmkd創建名稱爲lmkd的socket,節點位於/dev/socket/lmkd,接受命令如下:
功能 | 命令 | 對應方法 |
---|---|---|
LMK_PROCPRIO | 設置進程adj | PL.setOomAdj() |
LMK_TARGET | 更新oom_adj | PL.updateOomLevels() |
LMK_PROCREMOVE | 移除進程 | PL.remove() |
設置adj
- 向節點/proc//oom_score_adj寫入oom_adj。
framework與lmkd對應方法:
static void ctrl_command_handler(void) {
int ibuf[CTRL_PACKET_MAX / sizeof(int)];
int len;
int cmd = -1;
int nargs;
int targets;
len = ctrl_data_read((char *)ibuf, CTRL_PACKET_MAX);
if (len <= 0)
return;
nargs = len / sizeof(int) - 1;
if (nargs < 0)
goto wronglen;
//將網絡字節順序轉換爲主機字節順序
cmd = ntohl(ibuf[0]);
switch(cmd) {
case LMK_TARGET:
targets = nargs / 2;
if (nargs & 0x1 || targets > (int)ARRAY_SIZE(lowmem_adj))
goto wronglen;
cmd_target(targets, &ibuf[1]);
break;
case LMK_PROCPRIO:
if (nargs != 3)
goto wronglen;
//設置進程adj
cmd_procprio(ntohl(ibuf[1]), ntohl(ibuf[2]), ntohl(ibuf[3]));
break;
case LMK_PROCREMOVE:
if (nargs != 1)
goto wronglen;
cmd_procremove(ntohl(ibuf[1]));
break;
default:
ALOGE("Received unknown command code %d", cmd);
return;
}
return;
wronglen:
ALOGE("Wrong control socket read length cmd=%d len=%d", cmd, len);
}
- LMK_TARGET:AMS.updateConfiguration()的過程中調用updateOomLevels()方法, 分別向/sys/module/lowmemorykiller/parameters目錄下的minfree和adj節點寫入相應信息;
- LMK_PROCPRIO: AMS.applyOomAdjLocked()的過程中調用setOomAdj(),向/proc//oom_score_adj寫入oomadj 後直接返回;
- LMK_PROCREMOVE:AMS.handleAppDiedLocked或者 AMS.cleanUpApplicationRecordLocked()的過程,調用remove(),目前不做任何事,直接返回;
LowMemoryKiller Kernel driver
lowmemorykiller driver
位於drivers/staging/android/lowmemorykiller.c
核心在於:通過 register_shrinker
和unregister_shrinker
分別用於初始化和退出。
LMK通過註冊shrinker
來實現。其中shrinker
是Linux kernel標準的回收page的機制,由內核線程kswapd負責監控。
核心思想是
- 選擇oom_score_adj最大的進程中,並且rss內存最大的進程作爲選中要殺的進程。
- 殺進程方式:send_sig(SIGKILL, selected, 0)向選中的目標進程發送signal 9來殺掉目標進程。
內部使用:
lmkd參數
- oom_adj:代表進程的優先級, 數值越大,優先級越低,越容易被殺. 取值範圍[-16, 15]
- oom_score_adj: 取值範圍[-1000, 1000]
- oom_score:lmk策略中貌似並沒有看到使用的地方,這個應該是oom纔會使用。
lowmem_oom_adj_to_oom_score_adj 計算:
//OOM_SCORE_ADJ_MAX=1000
//OOM_DISABLE=-17
static int lowmem_oom_adj_to_oom_score_adj(int oom_adj)
{
if (oom_adj == OOM_ADJUST_MAX)
return OOM_SCORE_ADJ_MAX;
else
return (oom_adj * OOM_SCORE_ADJ_MAX) / -OOM_DISABLE;
}
- 當oom_adj = 15, 則 oom_score_adj = 1000;
- 當oom_adj < 15, 則 oom_score_adj = oom_adj * 1000/17;
小結
- 系統framework根據不同類型進程生命週期控制,動態分配不同的adj,並在不同時機進行更新。
- 更新adj時候在framework層會和lmkd守護進程進行通信,修改lmk deiver配置參數,設置/proc/pid/oom_score_adj;
- lowmemorykiller 驅動會被 linux 內核的內存 shrinker 機制調度,在 shrinker 操作中,計算進程 adj 和 rss,依據 driver 的 oom_adj 和 minfree 配置,進行 kill 進程操作