喜闻乐见-Android应用的生命周期
本文主要讲述了App的启动流程、Application的生命周期以及进程的回收机制。
在绝大多数情况下,每一个Android应用都在自己的Linux进程中运行。当需要运行某些代码时,进程就会被创建。进程将保持运行直到不再需要,当其他应用有需要的时候,系统会释放该进程的内存。
一个不常见但很基础的Android特性是,一个应用进程的生命周期并不是由应用本身直接控制的。它是由系统根据正在运行的程序,对用户的重要程度以及所占用的内存,综合去管理的。
1. App启动流程
此处讨论的是第一次启动App。在讲解App启动流程的时候,有两点需要知晓:
- 每一个App都运行在一个独立空间里,也可以称之为沙盒,这意味着它是在独立的线程中,拥有自己的虚拟机实例,被分配一个唯一的用户ID。
- App由很多不同组建组成,这些组件还可以调用其他App的组建,并没有一个单独的类似于main函数的入口。
总体来说,App启动分为三个步骤,创建进程、绑定Application以及启动Activity。当用户点击Android桌面一个App图标,启动一个应用的时候,整个流程如下所示:
点击事件通过Binder IPC机制最终被转换成startActivity(intent),而App相关信息的解析以及处理则在安装的时候就已经完毕。当startActivity的时候,ActivityManagerService(AMS)的操作如下:
- 第一步是intent解析。通过PackageManager的resolveIntent()方法,收集目标intent对象的信息。
- 第二步是权限检查。通过grantUriPermissionLocked()方法,检查用户是否有足够的权限去调用intent的目标组件。
- 第三步是创建新的任务。如果用户有足够的权限,ActivityManagerService就会检查目标Activity是否需要被加载在新的任务中。这个任务是根据Intent Flag来进行创建的。
最后检测进程记录表(ProgressRecord)是否存在。如果不存在,则需要通过ActivityManagerService来创建新的进程。
1.1 进程创建
ActivityManagerService通过调用startProcessLocked()方法来创建一个新的进程,这个方法会通过socket连接发送参数到Zygote进程。Zygote创建ActivityThread对象并返回新创建进程的pid。ActivityThread通过依次调用Looper.prepareLoop()和Looper.loop()方法开启消息循环。
1.2 绑定Application
当进程创建完毕后,需要将其与Application绑定起来。ActivityThread通过发送BIND_APPLICATION消息执行绑定,会执行makeApplication()方法将App的类加载进内存。
1.3 启动Activity
经过前面两步,系统拥有了与application相关联的进程,应用中相关的类被加载到进程的内存区域。在新创建或者已经存在的进程中启动Activity的步骤是一样的。ActivityThread通过发送LAUNCH_ACTIVITY消息进行启动操作。
大致梳理一下上面的过程,当用户点击应用图标的时候,系统会去检测进程是否存在,如果不存在,则通过Zygote创建进程,创建完进程后,则需要将进程与App进行绑定,将App的资源加载到内存中,当加载完毕,各种条件准备就绪,接下来就是启动Activity了,如此,App的界面就展示出来了。
2. Application生命周期
此处讨论的是Application类,而非应用生命周期。Application的作用,用官方文档的话说。
Base class for maintaining global application state.
它的作用是维护全局的应用状态的基类。Application类是应用中最先被初始化的类,先于Activity等组件。它的生命周期与Activity有几分相似,都经历了创建销毁过程,只不过它是一个线性的过程,不存在一些恢复过程。
2.1 onCreate
Called when the application is starting, before any activity, service, or receiver objects (excluding content providers) have been created.
当应用启动的时候调用,除了content providers之外,早于其他任何组件的创建。
2.2 onLowMemory
This is called when the overall system is running low on memory, and actively running processes should trim their memory usage.
当整个系统内存不足的时候,活跃的进程需要减少它们的内存使用的时候,回调会被调用。系统调用此回调过后,会产生一次GC操作。
2.3 onTerminate
This method is for use in emulated process environments.It will never be called on a production Android device, where processes are removed by simply killing them; no user code (including this callback) is executed when doing so.
在正式环境的真实设备上,不会被调用。由于系统结束进程采用的是kill的方法,因此不会产生相关的回调。
2.4 onTrimMemory
Called when the operating system has determined that it is a good time for a process to trim unneeded memory from its process.
当系统检测到应用可以回收不需要的内存时,会产生此回调。例如应用处于后台,系统内存不足的时候。
3. 回收机制
当系统出现低内存状况的时候,会根据不同进程的优先级进行内存回收。系统根据进程的状态,将进程分为四个等级。
3.1 Foreground Process
前台进程是优先级最高的进程,用户当前操作交互的必须是前台进程。当一个进程包含以下条件的时候,可以认为是前台进程。
- 用户正在交互的,处在屏幕最上层的Activity(onResume被调用过后)。
- 包含一个正在运行的BroadcastReceiver(onReceive正在执行)。
- 包含一个正在运行它的回调(onCreate、onStart、onDestroy)的service。
在一般状况下,杀死前台进程需要用户交互。当被系统杀死的时候,说明此时系统连该进程所需要的内存都无法满足,是最后才被杀死的。
3.2 Visible Process
可见进程是当前用户关心但是杀掉它会显著的影响用户体验的进程。当包含如下情况时,该进程可以被当做可见进程。
- 包含一个对用户可见但不在前台(onPause被调用过后)的Activity。
- 包含一个通过startForeground启动,正在运行的作为前台service的进程。
- 包含一些用户可感知的特定需求的service,例如动态壁纸、输入服务等。
可见进程一般不会被销毁,除非是为了保证所有前台进程的运行,而不得不杀死可见进程。
3.3 Service Process
服务进程是包含用startService所创建service的进程。这类进程对用户不是直接可见,但是用户会关心的,例如后台上传服务等等。所以系统会尽量维持它们的运行,除非系统内存不足以维持前台进程和可见进程的运行需要。
当service运行了很长的时间,例如超过30分钟,系统就会对其降级,以使该进程会被更容易的回收。
3.4 Cached Process
缓存进程是当前不被需要的进程,因此系统可以在任何需要内存的时候,释放掉它们的内存。
这类进程通常包含一个或多个当前不可见(onStop被调用)的Activity实例。当系统杀掉这类进程的时候,不会影响用户的体验。
3.5 不一致的地方
关于进程优先级,一般网上给出的前三种跟此处所列一致,不同之处是最后两种为后台进程以及空进程,而谷歌文档上,直接被归到缓存进程了。这个本身没有什么冲突,本质是一样的,谷歌根据进程对用户的重要程度划分的优先级,记住这个大方向就没啥问题了。
3.6 管理
关于进程的管理,首先需要知道Low Memory Killer(LMK)这个概念。它是基于Linux的Out of Memory Mechanism(OOM机制)改进而来的。LMK是一个内核层组件,是一个进程杀手。它的主要作用是在系统低内存状态时,释放掉那些不太重要进程的内存,让系统更加流畅。OOM只有当系统内存不足的时候才会启动检查,而LMK则不仅是在应用程序分配内存发现内存不足时启动检查,它也会定时地进行检查。
每一个进程根据其重要性,都包含一个oom_adj值,oom_adj的大小和进程的类型以及进程被调度的次序有关,AMS会去动态的更新oom_adj。当系统处在低内存状态时,LMK会根据oom_adj值大小,去杀死相关的进程。oom_adj值得范围是-17~15,一个进程的oom_adj值越高,它被杀死的概率就越大。
整个过程就是AMS更新oom_adj值,LMK去挑选并杀死进程。
4. 问题
ActivityManagerService的主要功能包括哪些?
可以看到,在安装App以及启动App的过程中,都有AMS的大量参与,它的主要功能包括以下几部分:
- 统一调度各应用程序的Activity
- 内存管理
- 进程管理
App的安装过程是怎样的?
Apk其实就是一个压缩包,系统安装App的过程,其实就是资源的解析、拷贝以及验证等过程。
PackageManagerService会将App中的Manifest信息解析出来,并持久化,当用户点击桌面icon的时候,系统就会知道该启动哪个组件。
PMS安装App,最后底层调用的也是adb命令来执行的。
大致来说,整个流程是,解析apk文件,执行安装过程,最后更新UI。
onLowMemory与onTrimMemory区别?
onLowMemory与onTrimMemory都是可以进行内存回收操作的地方,两者不同之处有以下几点:
- 两者API level不同,onLowMemory在API level 1就被添加了,而onTrimMemory是在API level 14中被添加的。当然,对于现在最低版本都是从十几开始支持的,完全可以直接使用onTrimMemory。
- 两者的触发时机不同,onLowMemory是在系统出现低内存状况时被触发,而onTrimMemory则是在置于后台而内存不足时被触发。
对于API 14以上的条件下,onTrimMemory在TRIM_MEMORY_COMPLETE
级别跟onLowMemory可以等同。
5. 参考
- Processes and Application Lifecycle
- Android Application Launch
- Android Application Launch Part 2
- Application
- Android application and activity life cycle - Tutorial
- Android系统APP安装流程解析
- android内核剖析学习笔记:AMS(ActivityManagerService)内部原理和工作机制
- Android源码解析之(十二)-->系统启动并解析Manifest的流程
- Android源码解析之(十三)-->apk安装流程
- How Android manages background processes?
- Android Low Memory Killer
- Android low memory killer 机制
- How to Tweak Android Low Memory Killer to Your Needs
喜闻乐见-Android应用的生命周期的更多相关文章
- Android Activity的生命周期简单总结
Android Activity的生命周期简单总结 这里的内容参考官方的文档,这篇文章的目的不是去总结Activity是如何启动,如何创造,以及暂停和销毁的,而是从实际开发中分析在Activity各个 ...
- android开发之生命周期
android开发之生命周期 一:Activity的生命周期: 这几天了了解了安卓Activity的生命周期,对于生命周期有了大概的理解: 一个Activity的生命周期也就是Activity从生成到 ...
- Android内的生命周期整理
1. Android App的生命周期: 2. Application的生命周期: 3. Activity的生命周期: 3.1 Fragment的生命周期: 4. Service的生命周期:5. Br ...
- Android开发——Activity生命周期
Android开发--Activity生命周期 Activity作为四大组件之首,也是使用最频繁的一种组件.本文将主要讲解Activity生命周期,包括正常情况下的Activity生命周期和异常情况下 ...
- 重温Android和Fragment生命周期
重温下Android和Fragment生命周期,理解生命周期方法的作用,什么时候调用,可以做一些什么操作. 1.Android生命周期 1.1 生命周期图 1.2 生命周期函数说明 onCreate: ...
- Xamarin.Android活动的生命周期
一.前言 用过Android手机的人一定会发现一种现象,当你把一个应用置于后台后,一段时间之后在打开就会发现应用重新打开了,但是之前的相关的数据却没有丢失.可以看出app的“生命”是掌握在系统手上的, ...
- Android:Activity生命周期
Android是使用任务(Task)来管理活动的,一个任务就是一组存放在栈里的活动的集合,这个栈也被称作返回栈(Back Stack). 栈是一种后进先出的数据结构,在默认情况下,每当我们启动了一个新 ...
- Android targetSdkVersion 对生命周期的影响
一直都认为当手机进入休眠时,Activity的生命周期会进入onPause()-->onStop()状态,但是今天偶然遇到了一个百思不得其解的问题,如果在AndroidMainfest.xml文 ...
- Android SurfaceView的生命周期
本文利用SurfaceView来实现视频的播放 本文地址:http://www.cnblogs.com/wuyudong/p/5851156.html,转载请注明源地址. 在main.xml布局文件添 ...
随机推荐
- Qt之实现网络下发配置的半透明友好提示界面
一.说明 在使用Qt开发的网管客户端程序中,网管客户端主要负责显示设备信息以及对设备下发配置信息等,如配置设备名字.更新设备程序等:由于在网管客户端程序的操作要先经过服务器处理,再由服务器将该命令转发 ...
- 【书籍推荐】java初级到中级书籍推荐
<编码>--必读 <程序是怎么跑起来的> --必读 <计算机系统概论> <深入理解计算机>--部分章节必读 <操作系统概论> <计算机 ...
- USB协议介绍
这里有必要先说清楚一下USB2.0规范的由来.USB2.0技术规范是有由Compaq.Hewlett Packard.Intel.Lucent.Microsoft.NEC.Philips共同制定.发布 ...
- python之getpass模块使用
我们登入linux时,输入密码是什么都不显示的,在python中也可以这样做,那就是getpass模块(在pycharm中无法使用) getpass模块中包含几个比较实用的功能: 1.getpass ...
- 对话Task
上一篇简单讲解了 线程和线程池以及上下文切换.创建线程代价高昂,默认每个线程都要占用大量虚拟内存1M.更有效的做法使用线程池,重复利用线程.在.NET4.0中引入了TPL任务并行库,你可以在将精力集中 ...
- 7z 程序打包 Demo
最近准备做一个用户端 异常收集的程序 需要收集用户机器的程序日志和相关信息 准备打包发回来 所以研究了一下7Z 文件压缩 做一个笔记吧 遇到的问题: 1:VS2008 遇到 loadlibrary ...
- 开源网站流量统计系统Piwik源码分析——后台处理(二)
在第一篇文章中,重点介绍了脚本需要搜集的数据,而本篇主要介绍的是服务器端如何处理客户端发送过来的请求和参数. 一.设备信息检测 通过分析User-Agent请求首部(如下图红线框出的部分),可以得到相 ...
- spring-boot-2.0.3启动源码篇五 - run方法(四)之prepareContext
前言 此系列是针对springboot的启动,旨在于和大家一起来看看springboot启动的过程中到底做了一些什么事.如果大家对springboot的源码有所研究,可以挑些自己感兴趣或者对自己有帮助 ...
- SpringMVC入门学习(二)
SpringMVC入门学习(二) ssm框架 springMVC 在上一篇博客中,我简单介绍了一下SpringMVC的环境配置,和简单的使用,今天我们将进一步的学习下Springmvc的操作. mo ...
- [转]微擎load()文件加载器
本文转自:https://blog.csdn.net/qq_32737755/article/details/78124534 微擎中加载文件需要用到 load() 在官网找到官方对load()的解释 ...