Android进程管理机制研究
一、Linux中的进程管理
在Linux中,进程是指处理器上执行的一个实例,可使用任意资源以便完成它的任务,具体的进程管理,是通过“进程描述符”来完成的,对应Linux内核中的task_struct数据结构。进程描述符,包括进程标识、进程的属性、构建进程的资源。
一个进程可以通过fork()或者vfork()调用创建出子进程,这些子进程可以访问父进程的地址空间,包括文本段、数据段、堆栈段。
通常情况下,调用fork()的进程处于task_running状态,则fork出来的子进程默认也处于task_running状态,具体来说,在fork之后、exec之前,子进程处于task_running状态中的就绪状态。
进程的运行状态包括以下几种。
1、task_running:可执行状态。包含正在CPU上执行的、可执行但是尚未被调度执行这两种子状态,后者对应就绪状态。
2、task_interruptible:可中断的睡眠状态。因为等待某事件的发生而被挂起。当等待的事件发生时,处于该状态的进程将被唤醒。
3、task_uninterruptible:不可中断的睡眠状态。处于睡眠状态,但是此刻进程是不可中断的。此时进程不响应异步信号,不能通过发送信号的方式kill之,但可以响应硬件中断,例如磁盘IO,网络IO等。
4、task_stopped / task_traced:暂停状态或跟踪状态。处于task_traced状态的进程不能响应SIGCONT信号而被唤醒,只能等到调试进程通过ptrace系统调用执行ptrace_cont、ptrace_detach等操作,或调试进程退出,被调试的进程才能恢复task_running状态。
5、task_zombie :僵尸状态。在进程收到SIGSTOP、SIGTTIN、SIGTTOU等信号,即将终止时,会进入该状态,此时进程成为僵尸进程。该状态的进程会处理一些资源释放工作,然后发送SIG_CHLD信号给父进程。
二、Android进程管理机制
在linux系统中,应用程序执行完成后,最终会清理一些进程使用的文件描述符、释放掉进程用户态使用的相关的物理内存,清理页表,然后发送信号给父进程。但在Android系统中,应用程序执行完成后,该应用所在的进程通常还是会在后台继续运行,除非应用程序在执行完成后主动调用System.exit或者Process.killProcess之类的方法。
这样设计的好处,主要是加快应用程序再次启动的速度,改善用户体验。当内存不足时,系统会按照特定规则,包括进程优先级、占用内存等信息,来清理进程并释放对应的资源。
1、进程优先级
在Android中,进程按优先级可以分为:前台进程、可见进程、服务进程、后台进程、空进程。优先级依次降低。
1)Forground,前台进程
这种进程优先级最高,可以细分下面几种情况:
case1:有个前台Activity,特指已经执行了onResume但还没执行onPause的Activity;
case2:有个Service且和一个前台Activity绑定的进程;
case3:调用了startForground的前台Service所在进程(这种服务会带个通知);
case4:正在执行onReceive函数的BroadcastReceiver所在进程,以及正在执行服务的生命周期方法诸如onCreate、onStartCommand的进程。
2)Visible,可见进程
可见进程没有处于前台的组件,但是用户仍然能看到进程中的组件,例如某进程的Activity调用了申请权限对话框,具体包括:
case1:有个仅onPause被调用的Activity(可见但被遮挡);
case2:进程中有个Service且和一个可见Activity绑定。
注意这里的可见Activity不包括前台Activity(否则就是前台进程了),并且这种进程在内存不足时也是可能被杀掉的。
3)Service,服务进程
服务进程是指有个通过startService方式启动的Service进程,并且不属于前面两类进程,例如MediaScannerService。
4)Background,后台进程
当前不可见的Activity所在进程属于后台进程,即它们的onStop被调用过,例如用户按下home键。
对于后台进程,系统会保存这些进程到一个LRU列表,当系统需要回收内存时,LRU中那些最近最少使用的进程将被杀死。
5)Empty,空进程
空进程不包含任何组件,当系统重新需要它们时(例如用户在别的进程中通过startActivity启动了它们),可以省去fork进程、创建Android运行环境等漫长的工作,节省时间,缓存性质。这种进程优先级最低,在任何时候都可能被杀掉。
如前所述,大部分应用是单进程的,但是进程和组件类型是高度关联的。如果应用中有生命周期差异较大的组件,考虑使用多进程分别处理。一方面是让占用资源较多的进程可以被系统及时回收,另一方面,避免那些需要长时间持续运行的任务由于组件生命周期的影响进入后台进程执行。
2、内存不足时的杀进程策略
在Linux系统中,进程的优先级对应一个参数,也就是oom_score_adj,lowmemorykiller程序会根据内存使用情况和进程优先级,动态杀进程以释放内存资源。
当内存不足或者发生oom错误时,lowmemorykiller根据特定策略先杀优先级最低的进程,然后逐步杀优先级更低的进程(同样优先级会按照内存占用情况排序),依此类推,以回收预期的可用系统资源,从而保证系统正常运转。
在Android系统中,进程的组件状态变化时,组件所在进程的优先级也会发生变化。一个典型的场景是,切换到后台的进程,其优先级低于前台进程。
App的前台/后台切换操作对oom_score_adj的影响,我们可以使用adb命令cat/proc/[pid]/oom_score_adj来查看。详细的优先级信息在ProcessList.java中有定义,对应的部分进程类型如下。
- Cached,缓存进程,包括空进程、只有activity的后台进程,其adj在900~906;
- B Services,无UI组件且在Lru进程表中位于后2/3的服务进程(比较旧的后台服务进程),其adj为800;
- Previous,上一个应用进程,例如按home键进入后台的进程,其adj为700;
- Home,也就是launcher进程,其adj为600;
- A Services,没有UI组件且在Lru进程表中位于后2/3的服务进程(比较旧的后台服务进程),其adj为500;
- Perceptible,有着用户可感知组件的进程,包括前台服务进程,adj为200;
- Visible,可见进程,其adj为100;
- Foreground,前台应用进程,其adj为0;
- Persistent,系统常驻进程,例如systemui、phone进程,其adj为-700或-800。如果是在AndroidManifest.xml中申明android:persistent="true"的进程,adj为-800;如果是由startIsolatedProcess()方式启动或由SystemServer进程、persistent进程绑定的服务进程,则为-700;
- System进程,典型的是SystemServer进程。
- Native进程,例如init、surfaceflinger、mediaserver进程,其adj为-1000;
内存不足时,AMS会根据上述动态优先级信息,通过ProcessRecord,在native层给指定进程发送信号以终止进程,进而释放内存资源。相关函数包括:killProcessesBelowForeground, killProcessesBelowAdj, ProcessRecord.kill, killPids等。
(相关完整且成体系的文章,可参见本人原创的开源电子书《Android系统与性能优化》,地址:https://github.com/carylake/androidnotes)
Android进程管理机制研究的更多相关文章
- 【朝花夕拾】Android性能篇之(六)Android进程管理机制
前言 Android系统与其他操作系统有个很不一样的地方,就是其他操作系统尽可能移除不再活动的进程,从而尽可能保证多的内存空间,而Android系统却是反其道而行之,尽可能保留进程.An ...
- Android内存进程管理机制
参考文章: http://www.apkbus.com/android-104940-1-1.htmlhttp://blog.sina.com.cn/s/blog_3e3fcadd0100yjo2.h ...
- Android内存管理机制之一:low memory killer
转载自http://www.miui.com/thread-29268-1-1.html 准备写这个专题之前,心里是有点忐忑的.首先Android内存管理机制相当复杂,想要讲清楚比较困难:其次对于绝大 ...
- Android包管理机制(二)PackageInstaller安装APK
前言 在本系列上一篇文章Android包管理机制(一)PackageInstaller的初始化中我们学习了PackageInstaller是如何初始化的,这一篇文章我们接着学习PackageInsta ...
- Android内存管理篇 - 从updateOomAdjLocked看lowmemorykiller之外的Android进程回收机制
提起android的进程回收机制,大家所熟知的是Android的lowmemroykiller的机制.当系统可用内存低于某个阀值时,即会杀死这个阀值对应的Adj值的所有应用.但是本篇文章并为是要介绍L ...
- Android 进程通信机制之 AIDL
什么是 AIDL AIDL 全称 Android Interface Definition Language,即 安卓接口描述语言.听起来很深奥,其实它的本质就是生成进程间通信接口的辅助工具.它的存在 ...
- Android包管理机制(一) PackageInstaller的初始化
前言 包管理机制是Android中的重要机制,是应用开发和系统开发需要掌握的知识点之一. 包指的是Apk.jar和so文件等等,它们被加载到Android内存中,由一个包转变成可执行的代码,这就需要一 ...
- Android进程回收机制LMK(Low Memory Killer)
熟悉Android系统的童鞋都知道,系统出于体验和性能上的考虑,app在退到后台时系统并不会真正的kill掉这个进程,而是将其缓存起来.打开的应用越多,后台缓存的进程也越多.在系统内存不足的情况下,系 ...
- 初探Linux进程管理机制
转至:http://ixdba.blog.51cto.com/2895551/543737 一 .进程的概念和分类1.进程的概念 Linux是一个多用户多任务的操作系统.多用户是指多个用户可以在同一时 ...
随机推荐
- redis centos 6.x 启动关闭脚本
#!/bin/sh #Configurations injected by install_server below.... EXEC=/usr/local/bin/redis-server CLIE ...
- VUE的中v-if和v-shou的区别
v-if的特点:每次都会重新删除或创建元素 v-shou的特点:每次执行都只是切换了元素的display:none的属性 v-if的缺点: 每次使用都会有较高性能消耗(频繁的切换元素建议不适用,建议使 ...
- JS的静态类型检测,有内味儿了
我们知道 TypeScript 2.3 以后的版本支持使用--checkJs对.js文件进行类型检查和错误提示. 但是由于 JavaScript 是弱类型语言,在编写代码的时候,是无法检测变量的类型的 ...
- 华为云·寻找黑马程序员#海量数据的分页怎么破?【华为云技术分享】
版权声明:本文为博主原创文章,遵循CC 4.0 BY-SA版权协议,转载请附上原文出处链接和本声明. 本文链接:https://blog.csdn.net/devcloud/article/detai ...
- luogu P1754 球迷购票问题
题目背景 盛况空前的足球赛即将举行.球赛门票售票处排起了球迷购票长龙. 按售票处规定,每位购票者限购一张门票,且每张票售价为50元.在排成长龙的球迷中有N个人手持面值50元的钱币,另有N个人手持面值1 ...
- 使用 Zookeeper 的 Api 实现服务订阅
服务提供者 服务提供者中拷贝 Constants 服务提供者中拷贝 UserService 连接 Zk 集群 /*** * 连接ZooKeeper集群 */ public ZooKeeper conn ...
- 初次接触tensorflow
要确保已经明白神经网络和卷积神经网络的原理.如果不明白,先学习参考资料1.tensorflow中有很多api,可以分成2大类.1类是比较低层的api(tf.train),叫TensorFlow Cor ...
- Asp.net Core 异常日志与API返回值处理
需求: 1.对异常进行捕获记录日志 并且修改返回值给前端 解释: ILogger4是自定义的一个日志,更改它就好 解决方案1: 使用中间件进行异常捕获并且修改其返回值 public class Err ...
- 视频发布 2019 中国.NET 开发者峰会
2019 年,注定会是 .NET Core 社区发展的关键一年,诸多重大事件在这一年发生!正如大家所期待的那样,刷新中国 .NET 社区的年度盛会--2019 中国 .NET 开发者峰会(.NET C ...
- 【Vuejs】351- 带你解析vue2.0的diff算法
前言 vue2.0加入了virtual dom,有向react靠拢的意思.vue的diff位于patch.js文件中,该算法来源于snabbdom,复杂度为O(n).了解diff过程可以让我们更高效的 ...