SAKA'S BLOG

进程和线程的生命周期

在大多数情况下每个安卓应用都运行在它自己的Linux进程中。
这个进程在应用的代码需要执行的时候创建,
直到不再需要它并且系统需要为其他应用重新申请内存的时候才会销毁。

安卓的一个不寻常的基本特征时应用程序的生命周期不受应用程序本身直接控制。
而是由系统通过系统了解到的正在运行的部分应用的组合,
这些程序对用户的重要性以及系统中可用的整体内存来确定。

不正确的使用组件(activity,service,broadcastreceiver)会导致当程序运行时程序进程被系统杀死。

进程生命周期错误的一个常见问题时关于BroadcastReceiver,
它在BroadcastReceiver.onReceive()方法中接收到intent时启动一个线程,然后从该函数返回。
一旦返回,系统会认为BroadCastReceiver不再是活动的,
因此它的持有进程不再是必须的(除非其他的应用程序中的组件在这个进程中是活跃的)。
因此它的持有进程可能会随时被杀死以回收内存,
这样做会终止在进程运行的线程。
这中问题的解决方案通常是使用一个Josservice来管理BroadcastReceiver,
这样系统知道进程中仍然有未完成的工作。

为了确定哪些进程在内存不足时应该被杀死,
安卓系统会根据运行的组件和这些组件的状态将每个进程置于“重要性层次结构”中。 按重要性顺序:

  1. 前台进程(foreground process)

前台进程是用户当前正在操作的进程。
各种应用程序组件可以使其包含的进程以不同的方式被修同视为前台。
如果满足以下条件之一,则认为进程处于前台:

  • 它正在屏幕顶部运行与用户交互的Activity(已调用其onResume()方法)。
  • 它有一个BroadcastReceiver正在运行(它的BroadcastReceiver.onReceive()方法正在执行)。
  • 它具有当前正在其一个回调方法(Service.onCreate(),Service.onStart()或Service.onDestroy())中执行的service。
    这些进程只有当系统的内存太低太低的时候,甚至连这些进程都不能继续运行,才会被杀死。
  1. 可见进程(visible process)

可见进程是正在工作的进程,杀死它将对用户体验产生显著的负面影响。

  • 它正在运行一个对用户屏幕上可见但不在前台的Activity(其onPause()方法已被调用)。
    这可能会发生,例如,如果前台活动显示为允许在其后面看到之前的活动的对话框。

  • 它具有作为前台服务运行的服务,通过Service.startForeground()
    (它要求系统将该服务视为用户知道的内容,或对其基本可见)。

  • 它正在托管系统用于用户知道的特定功能的服务,例如实况壁纸,输入法服务等。

在系统中运行的这些进程的数量少于前台进程的限制,但仍然相对受控。
这些进程被认为是非常重要的,不会被杀死,除非这样做是为了保持所有前台进程的运行。

  1. 服务进程(service process)
    服务进程是一个持有已经以startService()方法启动的service的进程。
    虽然这些进程对用户来说不是直接可见的,
    但它们通常是用户关心的事情(例如后台网络数据上传或下载),
    因此系统将始终保持这些进程的运行,
    除非没有足够的内存来保留所有前台进程和可见进程。

已经运行了很长时间(例如30分钟或更长时间)的service可能被降级,
允许他们的进程丢弃到下面描述的缓存的LRU列表中。
这有助于避免长时间运行的内存泄漏服务或其他问题消耗这么多RAM的情况,
从而阻止系统有效使用缓存进程。

  1. 缓存进程(cached process)
    缓存过程是当前不需要的进程,
    因此当需要其更多存时,系统可以随意杀死它。
    在正常的系统中,下面是内存管理中唯一的过程:
    运行良好的系统将具有始终可用的多个缓存进程(用于在应用程序之间进行更有效的切换),
    并根据需要定期杀死最老的进程。
    只有在非常关键(和不可取的)情况下
    ,系统才能达到所有缓存进程被杀死的程度,并且必须开始杀死服务进程。

这些进程通常保存用户当前不可见的一个或多个Activity实例(已调用并返回onStop()方法)。
如果系统正确执行其活动生命周期,当系统杀死此类进程时,
在返回到该应用程序时不会影响用户的体验:
当相关联的活动重新创建时,可以恢复以前保存的状态一个新的过程。

这些进程保存在伪LRU列表中,
其中列表中的最后一个进程首次被终止以回收内存。
在这个列表上的具体策略是平台的实现细节,
但是通常会在其他类型的进程之前保留更多有用的进程(一个托管用户的home应用程序,他们看到的最后一个活动等)。
还可以应用其他方法来销毁进程:允许的进程数量的严格限制,进程可以不断缓存的时间限制等。

在决定如何对进程进行分类时,
系统将根据当前处于活动状态的所有组件中找到的最重要的级别进行决策。

进程的优先级也可以基于其他进程对它的依赖性而增加。
例如,如果进程A已经绑定到具有Context.BIND_AUTO_CREATE标志的服务或正在进程B中使用ContentProvider,
那么进程B的分类将始终至少与进程A一样重要。