1 android 作为移动设备的操作系统,可能出现管理的内部不足的情况,为了尽量保证程序继续运行,需要有机制处理相关的内存问题。
2 Android 操作系统是基于linux的,linux 系统具有缓存内存的功能,即为了加快下次的速度,打开文件后放到内存中,再关闭后不会自动释放掉该内存,所以是cache memory。
会出现linux设备内存有多大,linux系统就会尽量多占用内存,减少下次启动的时间。再内存不够用的时候才会去释放。
Android 设备延用了linux的这个机制,但做了部分的优化,不是缓存文件等,而是缓存进程,但打开一个app后,会创建该app的进程,退出app时不会立刻关掉该进程,所以该进程会占用部分内存。这样的优点是加快下次打开apk的速度。
3 Linux 有oom的机制,在内存不足时释放以让当前程序跑下去。android 同样也有oom处理机制(low memory killer).
4 内存不足时,杀掉谁腾出内存空间是有定义一个rule, 正常理解肯定是先杀手无用的且占内存较大的进程,保证前台显示的进程正常使用。
如driver中有一个数组,
如下,当内存少爷16 * 1024 (64m)时会杀手adj > 12的进程。
kernel 4.12 之前lmk 在内核中
drivers/staging/android/lowmemorykiller.c
static u32 lowmem_debug_level = 1;
static short lowmem_adj[6] = {
0,
1,
6,
12,
};
static int lowmem_adj_size = 4;
static int lowmem_minfree[6] = {
3 * 512, /* 6MB */
2 * 1024, /* 8MB */
4 * 1024, /* 16MB */
16 * 1024, /* 64MB */
};
5 kernel 4.12之后lmk 已经在内核中删除,使用用户空间的lmkd 执行该功能。
https://source.android.com/devices/tech/perf/lmkd
Historically, Android monitored system memory pressure using an in-kernel low memory killer (LMK) driver, a rigid mechanism that depends on hard-coded values. As of kernel 4.12, the LMK driver is removed from the upstream kernel and the userspace lmkd performs memory monitoring and process killing tasks.
用户空间的lmkd的code路径
system/memory/lmkd/
https://source.android.com/devices/tech/perf/lmkd
6 android 定义了adj,lmkd就是根据这个adj值去判断杀手哪个进程, adj就是rule的体现。
如下面重要的process,有些adj值比较小,lmkd 一般不会杀掉,大的值lmkd就会有被杀手的风险。
/proc/1/oom_score_adj 值为-1000 --- NATIVE_ADJ
/proc/2/oom_score_adj 值为0 --- FOREGROUND_APP_ADJ
/proc/1571/oom_score_adj 值为-800 ---PERSISTENT_PROC_ADJ
/proc/1711/oom_score_adj 值为200 --- PERCEPTIBLE_APP_ADJ
/proc/4283/oom_score_adj 值为100 -- VISIBLE_APP_ADJ
/proc/1608/oom_score_adj 值为600 --- HOME_APP_ADJ
/proc/2846/oom_score_adj 值为700 -- PREVIOUS_APP_ADJ
/proc/5155/oom_score_adj 值为900 --- CACHED_APP_MIN_ADJ
这边定义得adj值
frameworks/base/services/core/java/com/android/server/am/ProcessList.java
UNKNOWN_ADJ | 1001 | Undetermined adj, usually the process to be cached |
CACHED_APP_MAX_ADJ | 999 | Maximum adj for invisible processes |
CACHED_APP_MIN_ADJ | 900 | Adj minimum for invisible processes |
SERVICE_B_ADJ | 800 | Compared with a list, the service in B list has a smaller adhesion to users |
PREVIOUS_APP_ADJ | 700 | User’s previous interaction process |
HOME_APP_ADJ | 600 | Launcher process |
SERVICE_ADJ | 500 | Application service process |
HEAVY_WEIGHT_APP_ADJ | 400 | Heavyweight processes in the background |
BACKUP_APP_ADJ | 300 | Processes that host backup related operations |
PERCEPTIBLE_APP_ADJ | 200 | Perceptible processes, such as background music playback |
VISIBLE_APP_ADJ | 100 | Activity process visible in the foreground |
FOREGROUND_APP_ADJ | 0 | The process currently running in the foreground, that is, the program the user is interacting with |
PERSISTENT_SERVICE_ADJ | -700 | Process bound to system process or persistent process |
PERSISTENT_PROC_ADJ | -800 | The process of the persistent property, such as telephone |
SYSTEM_ADJ | -900 | System process |
NATIVE_ADJ | -1000 | Native process, not managed by the system |
7 android 提供方法,方便apk 和 bin档调整优先级,针对重要的apk或进程防止被lmk给杀掉。
系统同时也会动态设置apk 的adj值,当打开一个apk,前台时 adj为FOREGROUND_APP_ADJ, 退出到后台adj就变成了PREVIOUS_APP_ADJ。
Android AMS的OomAdjuster 就是专门处理这个事情,有对四大组件activity/service/broadcast receiver/content provider分别根据不同的情况设置相应的adj值。
frameworks/base/services/core/java/com/android/server/am/OomAdjuster.md
这边给了OOM调节的设计原理及主要功能
frameworks/base/services/core/java/com/android/server/am/OomAdjuster.java
逻辑较多
private boolean computeOomAdjLSP(ProcessRecord app, int cachedAdj,
ProcessRecord topApp, boolean doingAll, long now, boolean cycleReEval,
boolean computeClients) {
。。。。
// important to least, and assign an appropriate OOM adjustment.
int adj;
int schedGroup;
int procState;
int cachedAdjSeq;
int capability = 0;
boolean foregroundActivities = false;
boolean hasVisibleActivities = false;
if (PROCESS_STATE_CUR_TOP == PROCESS_STATE_TOP && app == topApp) {
。。。
} else if (state.isRunningRemoteAnimation()) {
。。。
} else if (app.getActiveInstrumentation() != null) {
。。。
} else if (state.getCachedIsReceivingBroadcast(mTmpBroadcastQueue)) {
。。。
} else if (psr.numberOfExecutingServices() > 0) {
。。。
} else if (app == topApp) {
。。。
} else {
。。。
}
。。。
// Examine all activities if not already foreground.
if (!foregroundActivities && state.getCachedHasActivities()) {
。。。
schedGroup = state.getCachedSchedGroup();
}
if (procState > PROCESS_STATE_CACHED_RECENT && state.getCachedHasRecentTasks()) {
。。。
}
if (adj > ProcessList.PERCEPTIBLE_APP_ADJ
|| procState > PROCESS_STATE_FOREGROUND_SERVICE) {
if (psr.hasForegroundServices()) {
。。。
} else if (state.hasOverlayUi()) {
。。。
}
}
// If the app was recently in the foreground and moved to a foreground service status,
// allow it to get a higher rank in memory for some time, compared to other foreground
// services so that it can finish performing any persistence/processing of in-memory state.
if (psr.hasForegroundServices() && adj > ProcessList.PERCEPTIBLE_RECENT_FOREGROUND_APP_ADJ
&& (state.getLastTopTime() + mConstants.TOP_TO_FGS_GRACE_DURATION > now
|| state.getSetProcState() <= PROCESS_STATE_TOP)) {
。。。
}
if (adj > ProcessList.PERCEPTIBLE_APP_ADJ
|| procState > PROCESS_STATE_TRANSIENT_BACKGROUND) {
。。。
}
if (state.getCachedIsHeavyWeight()) {
。。。
}
if (state.getCachedIsHomeProcess()) {
。。。
}
if (state.getCachedIsPreviousProcess() && state.getCachedHasActivities()) {
。。。
}
。。。
for (int is = psr.numberOfRunningServices() - 1;
is >= 0 && (adj > ProcessList.FOREGROUND_APP_ADJ
|| schedGroup == ProcessList.SCHED_GROUP_BACKGROUND
|| procState > PROCESS_STATE_TOP);
is--) {
ServiceRecord s = psr.getRunningServiceAt(is);
if (s.startRequested) {
。。。
}
。。。
}
final ProcessProviderRecord ppr = app.mProviders;
for (int provi = ppr.numberOfProviders() - 1;
provi >= 0 && (adj > ProcessList.FOREGROUND_APP_ADJ
|| schedGroup == ProcessList.SCHED_GROUP_BACKGROUND
|| procState > PROCESS_STATE_TOP);
provi--) {
ContentProviderRecord cpr = ppr.getProviderAt(provi);
for (int i = cpr.connections.size() - 1;
i >= 0 && (adj > ProcessList.FOREGROUND_APP_ADJ
|| schedGroup == ProcessList.SCHED_GROUP_BACKGROUND
|| procState > PROCESS_STATE_TOP);
i--) {
。。。
}
。。。
}
。。。
if (s.isForeground) {