在大多数情况下,每个Android应用程序都在自己的Linux进程中运行。当需要运行某些代码时,将为应用程序创建此过程,并且该过程将一直运行,直到不再需要它为止,并且系统需要回收其内存以供其他应用程序使用。
Android的一个不寻常的基本特征是应用程序进程的生命周期不是由应用程序本身直接控制的。相反,它由系统通过系统知道正在运行的应用程序部分的组合,这些事物对用户的重要性以及系统中可用的总体内存量来确定。
应用程序开发人员必须了解不同的应用程序组件(特别是Activity,Service和BroadcastReceiver)如何影响应用程序进程的生命周期。不正确使用这些组件会导致系统在执行重要工作时终止应用程序的进程。
进程生命周期错误的一个常见示例是BroadcastReceiver,它在BroadcastReceiver.onReceive()方法中接收Intent时启动一个线程,然后从该函数返回。一旦返回,系统会认为BroadcastReceiver不再处于活动状态,因此不再需要其托管进程(除非其他应用程序组件处于活动状态)。因此,系统可能随时终止进程以回收内存,并且这样做会终止在进程中运行的生成的线程。此问题的解决方案通常是从BroadcastReceiver安排JobService,以便系统知道在该过程中仍有活动的工作。
为了确定在内存不足时应该杀死哪些进程,Android会根据其中运行的组件以及这些组件的状态将每个进程置于“重要性层次结构”中。 这些流程类型(按重要性排序):
1、前台进程是用户当前正在执行的操作所必需的进程。
各种应用程序组件可以使其包含进程以不同方式被视为前景。 如果满足以下任何条件,则认为进程处于前台:
- 它在用户正在与之交互的屏幕顶部运行一个Activity(已调用其onResume()方法)。
- 它有一个当前正在运行的BroadcastReceiver(它的BroadcastReceiver.onReceive()方法正在执行)。
- 它有一个服务,当前正在其一个回调中执行代码(Service.onCreate(),Service.onStart()或Service.onDestroy())。
在系统中只会有一些这样的过程,如果内存太低甚至这些过程都不能继续运行,这些过程只会作为最后的手段被杀死。 通常,此时,设备已达到内存分页状态,因此需要此操作以保持用户界面响应。
2、一个可见的过程正在进行用户当前意识到的工作,因此杀死它会对用户体验产生明显的负面影响。
在以下条件下,可以看到一个过程:
- 它正在运行一个活动,该活动在屏幕上对用户可见,但不在前台(已调用其onPause()方法)。 例如,如果前景Activity显示为允许在其后面看到前一个Activity的对话框,则可能会发生这种情况。
- 它有一个作为前台服务运行的服务,通过Service.startForeground()(它要求系统将服务视为用户知道的东西,或者对它们基本上是可见的)。
- 它正在托管系统用于用户知道的特定功能的服务,例如动态壁纸,输入法服务等。
在系统中运行的这些进程的数量比前台进程更少,但仍然是相对受控的。 这些进程被认为是非常重要的,除非需要这样做以保持所有前台进程运行,否则不会被杀死。
3、服务进程是一个持有使用startService()方法启动的服务的进程。
虽然用户不能直接看到这些进程,但它们通常是用户关心的事情(例如后台网络数据上传或下载),因此系统将始终保持这些进程运行,除非没有足够的内存来保留所有进程 前景和可见过程。
已经运行了很长时间(例如30分钟或更长时间)的服务可能会被降级,以允许其进程下降到下面描述的缓存LRU列表。 这有助于避免出现内存泄漏或其他问题的长时间运行服务占用大量RAM而导致系统无法有效使用缓存进程的情况。
4、缓存进程是当前不需要的进程,因此当其他地方需要内存时,系统可以根据需要自由地终止进程。
在正常运行的系统中,这些是内存管理中涉及的唯一过程:运行良好的系统将始终具有多个缓存进程(用于在应用程序之间进行更有效的切换),并根据需要定期终止最旧的进程。只有在非常关键(且不可取)的情况下,系统才会到达所有缓存进程被杀死的点,并且必须开始终止服务进程。
这些进程通常包含一个或多个当前对用户不可见的Activity实例(已调用并返回onStop()方法)。如果他们正确地实现了他们的活动生命周期(请参阅活动以获取更多详细信息),当系统终止此类流程时,它不会影响用户返回该应用程序时的体验:它可以在重新创建关联活动时恢复以前保存的状态一个新的过程。
这些进程保存在伪LRU列表中,列表中的最后一个进程是第一个被回收内存的进程。在此列表上排序的确切策略是平台的实现细节,但通常它会尝试在其他类型的进程之前保留更多有用的进程(一个托管用户的主应用程序,他们看到的最后一个活动等)。还可以应用其他用于终止进程的策略:对允许的进程数量的硬限制,对进程可以持续缓存的时间量的限制等。
在决定如何对流程进行分类时,系统将根据流程中当前活动的所有组件中最重要的级别做出决策。 有关每个组件如何对流程的整个生命周期做出贡献的更多详细信息,请参阅Activity,Service和BroadcastReceiver文档。 每个类的文档都更详细地描述了它们如何影响其应用程序的整个生命周期。
还可以基于进程对其具有的其他依赖性来增加进程的优先级。 例如,如果进程A已使用Context.BIND_AUTO_CREATE标志绑定到Service,或者正在进程B中使用ContentProvider,则进程B的分类将始终至少与进程A一样重要。
网友评论