上文主要介绍了Andorid内存的管理机制,本文对其中的LMK机制进行深入扩展总结。
我们知道出现Crash应用闪退和崩溃一般有三个原因:ANR(程序无响应)、Exception(异常)、LMK(低内存杀死机制)。本文重点介绍LMK机制。
目的:了解LMK原理,探究进程保活的方案和程序异常处理的方法。
KMK,(Low Memory Killer )低内存杀死机制。由于Android应用的沙箱机制,每个应用程序都运行在一个独立的进程中,各自拥有独立的Dalvik虚拟机实例,系统默认分配给虚拟机的内存是有限度的,当系统内存太低依然会触发LMK机制,即出现闪退、崩溃现象。
不同厂商不同,如:华为mate7,192M ;小米4,128M ;红米,128M 。而在,Android4.0以后,可以通过在application
节点中设置属性android:largeHeap=”true”
来设置最大可分配多少内存空间就可以突破一定限制。
OOM(OutOfMemoryError)内存溢出错误 。导致OOM的两个主要原因:
1、内存泄漏,大量无用对象未及时回收,导致后续申请内存失败。
2、BitMap大对象,几个大图同时加载很容易触发OOM。
通过阅读本文,可以了解Android LMK机制,从而避免App被频繁的杀死,以及一些开发中会遇到的问题。
为了空出足够的内存供前台进程使用,Android会定时进行CHECK进程树,然后杀死优先级别不高的进程。而进程的优先级别是按照属性 oom_adj 来判断的。oom_adj数值越低,越不会被杀死。
oom_adj
的数字大致为这几种:
FOREGROUND_APP_ADJ | 0 | 前台进程,正在活动的Activity或者使用startForeground的Service |
---|---|---|
VISIBLE_APP_ADJ | 1 | 可见进程,不可操作的Activity,但是可见 |
SECONDARY_SERVER_ADJ | 2 | 拥有后台服务器的进程 |
HIDDEN_APP_MIN_ADJ | 7 | Activity没有完全退出,直接采用 moveTaskToBack 到HOME的进程 |
CONTENT_PROVIDER_ADJ | 14 | 内容提供进程 |
EMPTY_APP_ADJ | 15 | 空程序,既不提供服务,也不提供内容 |
CORE_SERVER_ADJ | -12 | 系统进程 |
SYSTEM_ADJ | -16 | 系统核心服务(进程永远不会被杀掉) |
当系统的内存不足的时候,那么就会杀死发送KILL SIGNAL
, 杀死一些优先级别低的进程,用来提供足够的内存给前台进程使用。
用命令可以查看进程的优先级的值:
adb shell dumpsys activity|grep oom_adj
查看进程命令:
adb shell dumpsys activity processes
注意:
Low memory killer 是定时进行检查。
Low memory killer 主要是通过进程的oom_adj 来判定进程的重要程度。这个值越小,程序越重要,被杀的可能性越低。
oom_adj的大小和进程的类型以及进程被调度的次序有关。
LMK开始工作时,首先根据阈值表确定当前的警戒级数,则高于警戒级数的进程是待杀的范围。
然后遍历所有进程的oom_adj值,找到大于min_adj的进程,若找到多个,则把占用进程最大的进程存放在selected中。最关键的一步就是,发送SIGKILL信息,杀掉该进程。
一般情况下,Android会尽可能的保持应用进程,但在特定的场景会对进程进行Kill,例如为了清除旧进程来回收内存等。为了区分哪些进程最先被回收清理,而哪些不会,有一个优先级别,这就是Android的进程优先级,具体包括以下5种(优先级从高到低)。
Android主要通过LMK(Low Memory Killer)来对进程进行回收管理,LMK是在Android系统内存不足而选择kill部分进程释放空间,生死大权的决定者,其基于Linux的OOM机制,LMK通过oom_adj与占用内存的大小决定要杀死的进程,oom_adj值越小,越不容易被杀死。上面的几种进程形态对于的不同的oom_adj值。前台进程的优先级为0,普通service的进程优先级是8。
一方面提高进程优先级,降低被系统kill的概率。另一方面,在App被杀死以后进行拉活。知道了原理我们就可以采用一定的策略来提高应用的存活几率。
进程保活说白了就是保证自己App进程不死,App被杀死有以下几种可能:
了解LMK机制后,就可以对系统杀死的情况做相对应的优化。
androidmanifest.xml
中的application标签中加入android:persistent="true"
属性后的确就能够达到保证该应用程序所在进程不会被LMK杀死。但有个前提就是应用程序必须是系统应用,也就是说应用程序不能采用通常的安装方式。必须将应用程序的apk包直接放到/system/app目录下。而且必须重启系统后才能生效。
应用场景:定制TV端、平板端和手机端预装系统软件。
关键词:加入白名单、成为系统软件。
有些手机厂商把这些知名的app放入了自己的白名单中,保证了进程不死来提高用户体验(如微信、QQ、百度全家桶等在小米的白名单中)。如果从白名单中移除,他们终究还是和普通app一样躲避不了被杀的命运。
static final String STATE_SCORE = "playerScore";
static final String STATE_LEVEL = "playerLevel";
...
@Override
public void onSaveInstanceState(Bundle savedInstanceState) {
// 保存用户自定义的状态
savedInstanceState.putInt(STATE_SCORE, mCurrentScore);
savedInstanceState.putInt(STATE_LEVEL, mCurrentLevel);
// 调用父类交给系统处理,这样系统能保存视图层次结构状态
super.onSaveInstanceState(savedInstanceState);
}
说明:Activity 被系统回收了,在回收之前保存当前状态。
重写onSaveInstanceState()
方法,在此方法中保存需要保存的数据,该方法会在Activity被回收前调用。
通过重写onRetoreInstanceState()
方法可以从中提取保存好的数据。
Home
处理。将程序退到后台而不是kill程序。在根Activity中重写后退按钮响应事件,当按后退按钮的时候把Activity退置到后台
@Override
public boolean onKeyUp(int keyCode, KeyEvent event) {
if (keyCode == KeyEvent.KEYCODE_BACK) {
moveTaskToBack(true);
return true;
}
return super.onKeyUp(keyCode, event);
}
其中的moveTaskToBack
/**
* Move the task containing this activity to the back of the activity
* stack. The activity's order within the task is unchanged.
*
* @param nonRoot If false then this only works if the activity is the root
* of a task; if true it will work for any activity in
* a task.
*
* @return If the task was moved (or it was already at the
* back) true is returned, else false.
*/
public boolean moveTaskToBack(boolean nonRoot) {
try {
return ActivityManager.getService().moveActivityTaskToBack(
mToken, nonRoot);
} catch (RemoteException e) {
// Empty
}
return false;
}
说明:当nonRoot 为 false 时,当前activity必须为栈底,也就是最底层的activity,如果其他activity没有及时finish掉,就会出现异常,导致崩溃等情况的发生;nonRoot 为 true 时,不需要考虑当前activity是否在栈底。
系统统内存不足的时候肯定优先杀死这些占用内存高的进程来腾出资源。所以,为了尽量避免后台UI进程被杀,需要尽可能的释放一些不用的资源,尤其是图片、音视频之类的。对此,我们要想程序不被杀死,必须当前程序的内存占空间有比其他程序小才有竞争力不被优化kill掉。
最后在进一步总结LMK的机制和实际运用的意义时,看看这个博主是如何总结的:
关于了解LMK之后的内存管理建议:
了解Android LMK机制后,有助于在开发程序时 对系统的内存回收机制采取一定的措施来提高程序的体验性,同时最核心的问题还是在程序的开发内功上做指导意义,毕竟,如何管理好内存,是我们一直需要探讨和实践的问题。未完待续……
参考资料:
1.onSaveInstanceState()和onRestoreInstanceState()使用详解
2.Android之进程回收机制LMK(Low Memory Killer)
3.Android APP开发的内存管理与优化之一 ——LowMemory Killer