知识点
进程是一个动态的过程,每一个App的运行都是在一个独立的进程中,进程有自己独立的内存和数据空间,进程的名字就是App的packageName,这些进程都是从 Zygote 进程Fork出来的,并受AMS(ActivityManagerService)管理。
默认情况下,同一App的所有组件均在相同的进程中运行,但也可以允许App有多个进程。在 AndroidManifest.xml 里边给四大组件配置android:process属性,就可以让这些组件在指定的进程中运行,这些进程名字都是 packageName:name 这种,以区分是属于哪个App,我一般称之为辅助进程。
此外,您还可以设置 android:process(即不以“:”开头,以符合包命名的格式字符串为它的值),使不同应用的组件在相同的进程中运行,但前提是这些应用共享相同的Linux用户ID并使用相同的证书进行签署。
常有些开发不知道为什么自己的Application.onCreate中的代码执行了两次,如果你遇到这样的情况可以检查一下AndroidManifest.xml是否给某个组件配置了android:process属性。每个进程创建后,都会启动一个主线程(Looper接收消息),每个组件启动前都会先创建Application实例(一个进程只创建一个)。
优先级
当系统内存不足时,Android系统会选择终止掉一部份进程,回收其所占用的内存空间。 为了确定保留或终止哪些进程,系统会根据进程中正在运行的组件以及这些组件的状态,将每个进程放入“重要性层次结构”中。 必要时,系统会首先消除重要性最低的进程,然后是重要性略逊的进程,依此类推,以回收系统资源。
重要性从高到低如下所示:
- 前台进程
- 可见进程
- 服务进程
- 后台进程
- 空进程
其实也可以用优先级(oom_adj值)来表示这个重要性。App进程的优先级是在com.android.server.am.ProcessList
类里边定义的。所以当内存不足的时候,进程优先级低的(oom_adj越大的,系统进程是负数),占内存大的App进程将会被优先kill掉。
很多项目都比较“变态”,总想长期霸占内存(如消息推送),所以就有了各种进程保活的黑科技面市。黑科技我们占且不论,对于一般提高进程优先级的方法,大家还是应该了解一些。
如:
- 进程要运行一些组件,不要成为空进程。
- 远行一个Service,并设置为前台运行方式(startForeground)。
- AndroidManifest.xml中配置persistent属性(persistent的App会被优先照顾,进程优先级设置为PERSISTENT_PROC_ADJ=-12)
关于第2点,摘抄一段代码给大家看:
private void keepAlive() {
try {
Notification notification = new Notification();
notification.flags |= Notification.FLAG_NO_CLEAR;
notification.flags |= Notification.FLAG_ONGOING_EVENT;
startForeground(0, notification); // 设置为前台服务避免kill,Android4.3及以上需要设置id为0时通知栏才不显示该通知;
} catch (Throwable e) {
e.printStackTrace();
}
}
在Service的onCreate方法调用keepAlive()即可,其实就是是欺骗系统把自己当成一个一直在通知栏的Notification。不过这种方式,并不保证在所有的机型上都有效。
线程
线程是CPU调度的基本单元,一个应用都有一个主线程负责处理消息。一个应用启动后,至少会有3个线程,一个主线程(UI线程)和2个Binder线程。Zygote进程(APK所在的进程也是由Zygote进程Fork出来的)还会产生有一些Daemon线程如:ReferenceQueueDaemon、FinalizerDaemon、FinalizerWatchdogDaemon、HeapTaskDaemon,从名字大家也可以对它们的用途猜出一二。
线程间可以共享资源,为了保存UI的更新不会混乱,所以更新UI控件时要求在主线程进行更新,即需要保证更新UI是线程安全的。有时还可以问问面试者,什么是线程安全,貌似不知道这个概念的人也不少。
你的朋友是不是也在准备面试呢?你可以“请朋友读”,把今天的题目分享给好友,或许你能帮到他。