喜闻乐见-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布局文件添 ...
随机推荐
- Servlet案例5:用户登录失败信息回显
登录失败信息回显不会的新的一个页面,而是显示在登录页面 一种方法是: 登录页面表单中每个字段后添加<span>标签写入失败信息,利用ajax技术 通过改变<span>标签的di ...
- Python3基础语法你学会了么
编码 默认:源码文件以UTF-8编码,字符串都是unicode字符串 指定: 标识符 第一个字符:字母表中的字符或下划线 _ 其它部分:由字母.数字.下划线 _ 组成 大小写敏感 python ...
- 带你入门Python爬虫,8个常用爬虫技巧盘点
python作为一门高级编程语言,它的定位是优雅.明确和简单. 我学用python差不多一年时间了, 用得最多的还是各类爬虫脚本, 写过抓代理本机验证的脚本.写过论坛中自动登录自动发贴的脚本 写过自动 ...
- 一种基于python的人脸识别开源系统
今天在搜索人脸识别的文章时,无意中搜到一个比较开源代码,介绍说是这个系统人脸的识别率 是比较高的,可以达到:99.38%.这么高的识别率,着实把我吓了一跳.抱着实事求是的态度.个人 就做了一些验证和研 ...
- mongodb远程备份
创建备份用户 db.createUser({user: 'backup',pwd: 'back123' ,roles : [{role : 'userAdminAnyDatabase' ,db : ' ...
- 【sping揭秘】16、@After(finally) 但是这个实在afterturning之前执行
package cn.cutter.start.bean; import org.apache.commons.logging.Log; import org.apache.commons.loggi ...
- MD5加密之加密字符串
public static String encode(String str) { String encodeString = ""; try { MessageDigest md ...
- 《Kubernetes权威指南》——入门
1 Hello World 1.1 概述 搭建一个Web留言板应用,采用PHP+Redis. Redis由一个master提供写和两个slave提供读. PHP构成的前端Web层由三个实例构成集群,访 ...
- zmq setsockopt()
zmq.RCVTIMEO:在一个recv操作返回EAGAIN错误前的最大时间 设置socket的接收操作超时时间.如果属性值是0,zmq_recv(3)函数将会立刻返回,如果没有接收到任何消息,将会返 ...
- MySQL基准测试(一)--原因,策略,思路
MySQL基准测试(一)--原因,策略,思路 运用benchmark的原因 验证一些你认为的问题,通过基准测试和模拟数据来验证. 解决生产系统的一些异常 测试系统的当前的运行情况,通过历史的基准测试结 ...