5.2.3 进程回收算法
系统资源总是有限的,应用进程完成工作后都需要被回收,释放其占用的系统资源,把它留给其他的应用进程。在传统的应用模型中,应用进程的生命周期是由开发者把握的,当开发者觉得该应用的使命已经完成时,便发出相应的指令结束进程。但在Android中,每个应用进程的生命周期都是由系统来控制的,系统会根据进程优先级、资源状况等因素,决定何时回收应用进程。
Android对应用进程的回收秉承着几个原则:
1)尽量延长进程的生命周期,在资源允许的范围内,尽量不回收已创建的应用进程。
2)组件进程按照进程优先级从低到高进行回收。
3)同等优先级的进程,越近被使用过的越晚被回收。
在这些原则下,系统能够更充分地利用资源,提升系统的响应速度,并且保证用户体验不受进程回收的影响。
上一节曾介绍过,按照进程优先级,可将应用进程分成两个大类:“体验型”进程和“性能型”进程。在回收时,Android系统对这两类进程采取了不同的策略。
“性能型”进程的回收,发生在组件状态发生特定变化时,这些变化意味着组件所在的进程很有可能从“体验型”进程降级成为了“性能型”进程,从而导致“性能型”进程数量的增加,需要进行回收。具体的状态变化包括:
1)界面组件被销毁,即该组件的Activity.onDestroy函数被调用。
2)触发器组件执行完成,即该组件的BroadcastReceiver.onReceive函数执行完成。
3)触发器组件停止监听广播事件,即调用组件通过Context.registerReceiver函数注销了对应的触发器组件。
4)系统进入待机状态。
一旦被触发,就进入了“性能型”进程的回收阶段,算法流程如图5-4所示,主要包括以下几个步骤:
图 5-4 “性能型”进程的回收算法流程图
1)首先,Android会计算系统可接受的“性能型”进程的最大数量(预设的阈值通常为2),如果现有的“性能型”进程数量低于阈值,则无须回收。
2)如果“性能型”进程的数量高于阈值,系统则会尝试先行回收空进程。所有的空进程会按照最近的访问时间从晚到早依次回收,一旦剩余的“性能型”进程数量低于阈值,则进程回收流程结束。
3)如果所有的空进程都回收完毕,剩余的“性能型”进程数量依然高于阈值,系统则会开始回收后台进程。后台进程回收的逻辑,与空进程一致,同样是按照被访问时间从晚到早依次回收,直至进程数低于阈值。
通过上述步骤,可以将超出阈值的“性能型”进程全部回收。不难看出,“性能型”进程的回收机制是以进程数量为依据的,这是一种粗粒度的回收手段,对资源的控制不够精确。不同应用的进程消耗的资源数量千差万别,比如,浏览器应用进程可能会消耗大量的内存资源,而一个简单的计算器应用进程,则无须太多的内存支持。但在“性能型”进程的回收算法中,它们同样都按照“一个进程”的规格来进行回收。
为了解决这个问题,实现更精细地资源回收,当系统完成了“性能型”进程回收流程后,还会进入另一个回收流程,即后台界面组件的回收。后台界面组件的概念在上一节已经介绍过了,它包括除了前台界面组件和可视界面组件之外的其他界面组件对象。基于后台界面组件的回收是在进程内进行的,不会影响进程的数量和优先级,只是实现进程内部局部资源的释放。
每个应用进程中,都可能包含一些后台界面组件,系统会将所有的后台组件按照最近访问的时间统一排序。一旦后台界面组件的数量超出了预设的阈值(通常为20个),系统就会按照访问时间从晚到早依次回收后台界面组件。
在组件被回收前,Android会先调用Activity.onSaveInstanceState函数,将界面组件中的状态数据暂时写入到磁盘中,然后释放该组件对象,依次执行,直至剩余的后台组件数量符合阈值约束。
如果需要再次将该界面组件切换至前台状态,系统会重新构造该组件对象,并调用Activity.onRestoreInstanceState函数,将其恢复到被回收之前的状态,保持用户体验的一致性。整个回收流程,对于用户来说完全透明,与虚存机制有着异曲同工之处。
通过对后台界面组件的回收管理,系统可以更精确地控制内存资源,保证前台组件和进程的流畅运行。
除了对“性能型”进程的例行回收,Android系统还会时刻关注“体验型”进程的运行情况。当有新的应用进程被构造或者应用进程中的组件状态发生变化时,系统都会对各个进程的优先级进行调整,并按访问时间再次排序,重新分配系统资源。
系统会设定整个系统可运行的应用进程的最大阈值,当系统中的应用进程数超过阈值时,Android会强行回收长时间没被访问的进程,其中也可能包括“体验型”进程。从实际情况来看,前台进程和可视进程的数量通常较少,数量不易达到阈值,而服务进程是最易被回收的“体验型”进程。因此,在应用开发中,开发者需要妥善处理后台服务组件被回收的情况。
小贴士 进程和后台界面组件的回收可能会给应用带来一些Bug,但由于这样的回收仅会发生在资源紧张的情况下,一般不易在开发和测试中发现。所以,Android模拟器中提供了一个名为开发者工具(Dev Tool)的应用。通过它开发者可以强制系统回收进程或组件,以此来模拟在系统资源紧张的情况下应用运行的状况,发现一些隐藏其中的Bug。
如图5-5所示,开发者可以在开发者工具中设置进程和界面组件的回收方式,迫使系统立刻进行进程或组件的回收,这样就可以测试应用在这些非常状况下的表现了。
图 5-5 通过开发者工具控制进程和组件的回收