在Android开发中我们常常遇到app在后台长期不使用时被系统自动回收掉,Android系统是怎么实现这个功能的呢。我们不讨论如何让app保活的方法,主要来说说系统实现这一机制的原理
1、描述进程的重要程度——oom_adj
在Android系统中使用oom_adj值来描述一个进程的重要程度,它是AMS的Process类型中的一个变量,oom_adj值越小,表示进程越重要,越不容易被杀掉。以下是AMS中定义的一些oom_adj值
static final int EMPTY_APP_ADJ;
static final int HIDDEN_APP_MAX_ADJ;
static final int HIDDEN_APP_MIN_ADJ;
static final int HOME_APP_ADJ;
static final int BACKUP_APP_ADJ;
static final int SECONDARY_SERVER_ADJ;
static final int HEAVY_WEIGHT_APP_ADJ;
static final int PERCEPTIBLE_APP_ADJ;
static final int VISIBLE_APP_ADJ;
static final int FOREGROUND_APP_ADJ;
static final int CORE_SERVER_ADJ = -12;
static final int SYSTEM_ADJ = -16;
可以看到一些运行核心服务的进程的oom_adj为-12(CORE_SERVER_ADJ),这类进程基本不会被杀死。其他未赋值的都在static块中进行了初始化,是通过system/rootdir/init.rc进行配置的:
# Define the oom_adj values for the classes of processes that can be
# killed by the kernel. These are used in ActivityManagerService.
setprop ro.FOREGROUND_APP_ADJ 0
setprop ro.VISIBLE_APP_ADJ 1
setprop ro.SECONDARY_SERVER_ADJ 2
setprop ro.HIDDEN_APP_MIN_ADJ 7
setprop ro.CONTENT_PROVIDER_ADJ 14
setprop ro.EMPTY_APP_ADJ 15
# Define the memory thresholds at which the above process classes will
# be killed. These numbers are in pages (4k).
setprop ro.FOREGROUND_APP_MEM 1536
setprop ro.VISIBLE_APP_MEM 2048
setprop ro.SECONDARY_SERVER_MEM 4096
setprop ro.HIDDEN_APP_MEM 5120
setprop ro.CONTENT_PROVIDER_MEM 5632
setprop ro.EMPTY_APP_MEM 6144
可以看到前台进程的oom_adj值为0,这类进程时我们正在交互的进程,基本也不会被杀掉;空进程对应的值是15,当系统内存不足是最新杀掉的就是这类进程(这类进程一般指的是所有的activity都destory掉了,并且没有service在运行)。adj值下面描述的是各种内存阀值。比如当系统剩余内存小于6144 * 4kb(ro.EMPTY_APP_MEM)是emty 进程就会被回收掉。这些值对与每个手机厂商生产的手机都是不一样的。以下是oom_adj值对应的内存阀值
0 1536
1 2048
2 4096
7 5120
14 5632
15 6144
如上所说,当系统内存小于6144 * 4kb时empty进程将会被回收掉,而empty进程的oom_adj值为15。在Activity、service、contentProvider、Broadcast Android四大组件的状态的变化都会导致AMS更新对应进程oom_adj值,所以前台进程比后台进程更不容易杀掉,带有service的后台进程比没有service的进程更不容易被杀掉
2、LMK
LMK的全称是low memory killer,它是内核的一个模块。它里面保存了各个进程的pid以及对应的oom_adj,每次AMS调用updateOOmAdj函数更新进程的oom_adj时都会通知LMK模块。
LMK通过linux的shrinker模块来监听系统的内存变化,当系统的剩余内存达到某个阀值时就会杀掉oom_adj值大于这个阀值对应的oom_adj的进程。它会优先杀掉内存占用多的进程,如果杀掉这些进程内存回到了正常值将不会继续杀进程。所以让app不要占用大量的内存也可以起到保活的作用