android进程、线程的优先级

有一个面试问题:IntentService的优先级比单纯的线程高,它不容易被系统杀死,可以执行高优先级的后台任务。为什么?它的背后有那些逻辑呢?

IntentService的具体内容可以参照我的另外一篇文章:IntentService的源码分析,IntentService也是Service,后续就把IntentService改为Service了,更有代表性。表面看是涉及到两个知识点的问题,一是android进程优先级的问题,与gc有关,二是线程的优先级问题。其实弄清楚了android进程优先级的问题就可以回答上面的问题了,但是出于怕有人把Service的优先级与线程优先级问题混为一谈,这里也单独写一下线程优先级的问题。首先要说一点,Service的优先级与单纯的线程比较问题,其实是指(至少是服务进程)服务进程和空进程的优先级问题,单独的Service与线程优先级没有可比性。

1.进程优先级

android中进程的优先级与gc垃圾回收机制有关,当内存不足的时候,优先级越低的进程越容易被系统杀死,然后回收。

默认情况下, 同一个application中的所有组件运行在同一个linux进程下. 启动一个组件 A时, 如果已存在处于运行状态中的组件 B, 且A和B属于同一个application, 那么组件 A将在组件 B所在的进程下运行. 否则将为A创建一个新的linux进程.

开发者也可以为application中的组件指定不同的运行进程. manifest.xml文件中的<activity>, <service>, <receiver>, <provider>标签都支持android:process属性, 通过这个属性, 可以为组件指定运行的进程. <application>标签也支持设定android:process属性, 用于为application下的所有组件指定默认的运行进程.

进程优先级从高到低分别为5类,更具体的进程与优先级信息可以查看文章:Android平台App进程优先级


1. 前台进程

a.   进程拥有一个正在与用户交互的Activity(这个Activity的onResume()方法被调用)。

b.   进程拥有一个绑定到正在与用户交互的activity上的Service。

c.   进程拥有一个前台运行的Service — service调用了方法startForeground()。

d.   进程拥有一个正在执行其任何一个生命周期回调方法(onCreate(),onStart(),或onDestroy())的Service。

e.   程拥有正在执行其onReceive()方法的BroadcastReceiver。

系统中前台进程的数量很少, 前台进程几乎不会被杀死. 只有当内存低到无法保证所有的前台进程同时运行时才会选择杀死某个前台进程.

2.可视进程

a. 进程中包含未处于前台但仍然可见的activity(调用了activity的onPause()方法, 但没有调用onStop()方法). 典型的情况是运行activity时弹出对话框, 此时的activity虽然不是前台activity, 但其仍然可见.

可视进程不会被系统杀死, 除非为了保证前台进程的运行而不得已为之.

3. 服务进程. 

a. 进程中包含已启动的service,如运行着一个被startService()所启动的service。

尽管一个服务进程不直接影响用户所见,但是它们通常做一些用户关心的事情(比如播放音乐或下载数据),所以系统不到前台进程和可见进程活不下去时不会杀它。

4.后台进程

a.进程中包含不可见的activity(onStop()方法调用后的activity)。

这样的进程们不会直接影响到用户体验,所以系统可以在任意时刻杀了它们从而为前台、可见、以及服务进程们提供存储空间。通常有很多后台进程在运行。它们被保存在一个LRU(最近最少使用)列表中来确保拥有最近刚被看到的activity的进程最后被杀。如果一个activity正确的实现了它的生命周期方法,并保存了它的当前状态,那么杀死它的进程将不会对用户的可视化体验造成影响。因为当用户返回到这个activity时,这个activity会恢复它所有的可见状态。

5.空进程

a.一个进程不拥有入何active组件或者说不包含任何处于活动状态的进程。

系统经常杀死空进程, 这不会造成任何影响. 空进程存在的唯一理由是为了缓存一些启动数据, 以便下次可以更快的启动.

补充说明:

1.跟据进程中当前活动的组件的重要性,Android会把进程按排在其可能的最高级别。

例如,如果一个进程拥有一个service和一个可见的activity,进程会被定为可见进程,而不是服务进程。

2.由于组件之间的依赖性, 进程的优先级有可能被提高. 

假如进程A服务于进程B, 则进程A的优先级不能低于进程B. 比如, 进程A的ContentProvider组件正在服务于进程B的某个组件, 或者进程A的service组件和进程B的某个组件绑定等, 这些情况下, 进程A的优先级都不会低于进程B(如果按照优先级规则, 进程A的优先级确实低于进程B, 则系统会选择提高进程A的优先级到和进程B相同).

3.服务进程的优先级高于后台进程, 因此如果activity需要执行耗时操作, 最好还是启动一个service来完成. 当然, 在activity中启动子线程完成耗时操作也可以, 但是这样做的缺点在于, 一旦activity不再可见, activity所在的进程成为后台进程, 而内存不足时后台进程随时都有可能被系统杀死(但是启动service完成耗时操作会带来数据交互的问题, 比如耗时操作需要实时更新UI控件的状态的话, service就不是一个好的选择). 基于同样的考虑, 在BroadcastReceiver中也不应该执行耗时操作, 而应该启动service来完成(当然, BroadcastReceiver的生命周期过于短暂, 也决定了不能在其中执行耗时操作).


2.线程的优先级

谈到线程,要先说一下进程与线程的区别,可以参照文章:进程与线程

android中线程优先级与调用的顺序有关,优先级越高被调用的可能性越高,也就是说即使线程A的优先级高于线程B,同等情况下A不一定优于线程B被调用。

Android系统基于精简过后的linux内核,其线程的调度受时间片轮转和优先级控制等诸多因素影响。淡出认为某个线程分配到的time slice多少是按照其优先级与其它线程优先级对比所决定的,这并不完全正确。

Linux系统的调度器在分配time slice的时候,采用的CFS(completely fair scheduler)策略。这种策略不但会参考单个线程的优先级,还会追踪每个线程已经获取到的time slice数量,如果高优先级的线程已经执行了很长时间,但低优先级的线程一直在等待,后续系统会保证低优先级的线程也能获取更多的CPU时间。显然使用这种调度策略的话,优先级高的线程并不一定能在争取time slice上有绝对的优势,所以Android系统在线程调度上使用了cgroups的概念,cgroups能更好的凸显某些线程的重要性,使得优先级更高的线程明确的获取到更多的time slice。

Android将线程分为多个group,其中两类group尤其重要。一类是default group,UI线程属于这一类。另一类是background group,工作线程应该归属到这一类。background group当中所有的线程加起来总共也只能分配到5~10%的time slice,剩下的全部分配给default group,这样设计显然能保证UI线程绘制UI的流畅性。Android线程需要显示的指定线程的优先级,比如:

new Thread(new Runnable() {
  @Override
  public void run() {
    Process.setThreadPriority(Process.THREAD_PRIORITY_BACKGROUND);
  }
}).start();

决定新启一个线程执行任务的时候,首先要问自己这个任务在完成时间上是否重要到要和UI线程争夺CPU资源。如果不是,降低线程优先级将其归于background group。虽说Android系统在任务调度上是以线程为基础单位,但是设置单个thread的优先级也可以改变其所属的control groups,从而影响CPU time slice的分配。而且进程的属性变化也会影响到线程的调度,当一个App进入后台的时候,该App所属的整个进程都将进入background group,以确保处于foreground(用户可见)的新进程能获取到尽可能多的CPU资源。

====================================

参考文章:1.http://mrpeak.cn/blog/android-threading/

2. http://www.2cto.com/kf/201205/132324.html

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值