Android 进程生命周期 Process Lifecycle
进程的生命周期:
Android系统会尽力保持应用的进程,但是有时为了给新的进程和更重要的进程回收一些内存空间,它会移除一些旧的进程。为了决定哪些进程留下,哪些进程被杀死,系统根据在进程中在运行的组件及组件的状态,为每一个进程分配了一个优先级等级。
优先级最低的进程首先被杀死。
这个进程重要性的层次结构有五个等级,下面就列出这五种进程,按照重要性来排列,最重要的放在最前。
一.前台进程 Foreground process
前台进程是用户当前做的事所必须的进程,如果满足下面各种情况中的一种,一个进程被认为是在前台:1.进程持有一个正在与用户交互的Activity(Activity正处于onResume()的状态)。
2.进程持有一个Service,这个Service和用户正在交互的Activity绑定。
3.进程持有一个Service,这个Service是在前台运行的,即它调用了 startForeground()。
4.进程持有一个Service,这个Service正在执行它的生命周期回调函数(onCreate(), onStart(), or onDestroy())。
5.进程持有一个BroadcastReceiver,这个BroadcastReceiver正在执行它的 onReceive() 方法。
杀死前台进程需要用户交互,因为前台进程的优先级是最高的。
如果一个进程不含有任何前台的组件,但是仍然影响着用户在屏幕上可以看到的内容,就是可见进程。
可见进程满足下列情况之一:
1.进程持有一个Activity,这个Activity不在前台,但是仍然被用户可见(处于onPause()调用后又没有调用onStop()的状态)。
这种情况发生在,比如,前台的activity打开了一个对话框,这样activity就会在其后可见。
2.进程持有一个Service,这个Service和一个可见的(或者前台的)Activity绑定。
可见的进程也被认为是很重要的,一般不会被销毁,除非是为了保证所有前台进程的运行而不得不杀死可见进程的时候。
如果一个进程中运行着一个service,这个service是通过 startService() 开启的,并且不属于上面两种较高优先级的情况,这个进程就是一个服务进程。
尽管服务进程没有和用户可以看到的东西绑定,但是它们一般在做的事情是用户关心的,比如后台播放音乐,后台下载数据等。
四.后台进程 Background process
如果进程不属于上面三种情况,但是进程持有一个用户不可见的activity(activity的onStop()被调用,但是onDestroy()没有调用的状态),就认为进程是一个后台进程。后台进程不直接影响用户体验,系统会为了前台进程、可见进程、服务进程而任意杀死后台进程。
通常会有很多个后台进程存在,它们会被保存在一个LRU (least recently used)列表中,这样就可以确保用户最近使用的activity最后被销毁,即最先销毁时间最远的 activity。
如果一个进程不包含任何活跃的应用组件,则认为是空进程。
保存这种进程的唯一理由是为了缓存的需要,为了加快下次要启动这个进程中的组件时的启动时间。
系统为了平衡进程缓存和底层内核缓存的资源,经常会杀死空进程。
1.Android会尽可能地把进程放在高的优先级。
比如,一个进程拥有一个可见状态的activity和一个service,这个进程会被认为是可见进程,而不是服务进程。
2.一个进程的等级有可能会因为其他进程的依赖而提高,一个进程服务于另一个进程,则它的优先级不会比它服务的进程优先级低。
比如,A进程中的一个content provider向B进程中的一个客户提供服务,或A进程中的一个service被绑定在B进程中的一个组件上,则A进程的
优先级至少和B进程的优先级一样高。
3.因为服务进程的优先级比后台进程的优先级高,所以对于一个需要启动一个长时间操作的activity来说,开启一个service比创建一个工作
线程的方法更好,尤其是对于操作将很可能超出activity的持续时间时。
比如要上传一个图片文件,应该开启一个service来进行上传工作,这样在用户离开activity时工作仍在进行。使用service将会保证操作至少有服务进程的优先级。
Android 进程生命周期 Process Lifecycle
**********************************************************************************************************************************************************************************
**********************************************************************************************************************************************************************************
android 线程与进程 区别 联系
引入进程之前–多道程序设计概述
多道程序设计技术是操作系统最早引入的技术,它的设计思想是允多个程序同时进入内存并运行,其目的是为了CPU的利用率,进而提高系统效率
特点
多道程序设计技术引入之前,多个程序串行执行。只存在一个程序计数器(PC, program counter),一个程序执行完毕之后,才会执行下一个程序。而多道程序设计技术允许 多个程序同时进入内存并运行,那就要每个程序分配程序计数器。如果内存中有四个程序在并发执行,那就需要四个程序计数器。新技术带来的问题
一个技术、一个机制的引入,一方面解决了以前棘手的问题,但同时,往往带来新的问题。多道程序设计技术也是如此。
多道程序设计技术允许多个程序同时进入内存并运行,在这样的并发环境下,如何描述、刻画这样执行的程序呢?因此引入了“进程”。
进程(Process)
进程是具有独立功能的程序关于某个数据集合上的一次运行活动,是系统进行资源分配和调度(若不支持线程机制,进程的系统调度的单位。否则,线程是系统调度的单 位)的独立单位。
特点进程是程序的一次执行过程。若程序执行两次甚至多次,则需要两个甚至多个进程。
进程是是正在运行程序的抽象。它代表运行的CPU,也称进程是对CPU的抽象。(虚拟技术的支持,将一个CPU变幻为多个虚拟的CPU)
系统资源(如内存、文件)以进程为单位分配。
操作系统为每个进程分配了独立的地址空间
操作系统通过“调度”把控制权交给进程。
为什么引入线程 有了进程这概念之后 应用程序可以并发地去执行了 那么为什么要在进程当中再派生出线程呢?
为什么引入线程?
首先我们引入了进程这个概念,虽然进程有利于资源的管理和保护。然而在实际应用中,进程有这样的问题:
1. 进程切换的代价、开销比较大;
2. 在一个进程内也需要并行执行多个程序,实现不同的功能。
3. 进程有时候性能比较低。
引入线程有以下三个方面的考虑
1.应用的需要。比如打开一个浏览器,我想一边浏览网页,一边下载文件,一边播放音乐。如果一个浏览器是一个进程,那么这样的需求需 要线程机制。
2.开销的考虑。在进程内创建、终止线程比创建、终止进程要快。同一进程内的线程间切换比进程间的切换要快,尤其是用户级线程间的切换 。线程之间相互通信无须通过 内核(同一进程内的线程共享内存和文件)
3.性能的考虑。多个线程中,任务功能不同(有的负责计算,有的负责I/O),如果有多个处理器,一个进程就可以有很多的任务同时在执行
线程的属性:
线程
有标识符ID
有状态及状态转换,所以需要提供一些状态转换操作
不运行时需要保存上下文环境,所以需要程序计数器等寄存器
有自己的栈和栈指针
共享所在进程的地址空间和其它资源
进程与线程区别
1.定义方面:进程是程序在某个数据集合上的一次运行活动;线程是进程中的一个执行路径。
2.角色方面:在支持线程机制的系统中,进程是系统资源分配的单位,线程是系统调度的单位。
3.资源共享方面:进程间不能共享资源,而线程共享所在进程的址空间和其它资源。同时线程还有自己的栈和栈指针,程序计数器等寄存器。
4.独立性方面:进程有自己独立的地址空间,而线程没有,线程必须依赖于进程而存在。
Android中的进程和线程
在Android系统中,每一个App都是一个Linux用户。一般情况下,每个App都是运行在一个进程的一个线程中,这个线程习惯称为主线程(Main Thread).
Zygote是一个虚拟机进程,同时也是一个虚拟机实例的孵化器,每当系统要求执行一个 android应用程序,Zygote就会FORK出一个子进程来执行该应用程 序。 这样做的好处显而易见:Zygote进程是在系统启动时产生的,它会完成虚拟机的初始化,库的加载,预置类库的加载和初始化等等操作,而在系统需要一 个新的虚拟机实例时,Zygote通过复制自身,最快速的提供个系统。
另外,对于一些只读的系统库,所有虚拟机实例都和Zygote共享一块内存区域,大大节省了内存开销。
Android 进程模型
linux通过调用start_kernel函数来启动内核,当内核启动模块启动完成后,将启动用户空间的第一个进程——Init进程,下图为Android系统的进程模型图:
从上图可以看出,Linux内核在启动过程中,创建一个名为Kthreadd的内核进程,PID=2,用于创建内核空间的其他进程;同时创建第一个用户空间Init进程,该进程PID = 1,用
于启动一些本地进程,比如Zygote进程,而Zygote进程也是一个专门用于孵化Java进程的本地进程,上图清晰地描述了整个Android系统的进程模型
Zygote进程孵化新进程
下面来对Zygote进程孵化新进程的过程做进一步了解:
1.Zygote进程调用fork()函数创建出Zygote’ 子进程
2.子进程Zygote’ 共享父进程Zygote的代码区与连接信息
Fork()橙色箭头左边是Zygote进程,右边是创建出的Zygote‘子进程;然后Zygote’ 子进程将执行流程交给应用程序A,Android程序开
始运行。
新生成的应用程序A会使用已有Zygote父进程的库与资源的连接信息,所以运行速度很快。
另外,对于上图,Zygote启动后,初始并运行DVM,而后将需要的类与资源加载到内存中。随后调用fork()创建出Zygote’ 子进程,接着子进程动态加载并运行应用程序A。
运行的应用程序A会使用Zygote已经初始化并启动运行的DVM代码,通过使用已加载至内存中的类与资源来加快运行速度。