一、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进程管理机制研究的更多相关文章

  1. 【朝花夕拾】Android性能篇之(六)Android进程管理机制

    前言        Android系统与其他操作系统有个很不一样的地方,就是其他操作系统尽可能移除不再活动的进程,从而尽可能保证多的内存空间,而Android系统却是反其道而行之,尽可能保留进程.An ...

  2. Android内存进程管理机制

    参考文章: http://www.apkbus.com/android-104940-1-1.htmlhttp://blog.sina.com.cn/s/blog_3e3fcadd0100yjo2.h ...

  3. Android内存管理机制之一:low memory killer

    转载自http://www.miui.com/thread-29268-1-1.html 准备写这个专题之前,心里是有点忐忑的.首先Android内存管理机制相当复杂,想要讲清楚比较困难:其次对于绝大 ...

  4. Android包管理机制(二)PackageInstaller安装APK

    前言 在本系列上一篇文章Android包管理机制(一)PackageInstaller的初始化中我们学习了PackageInstaller是如何初始化的,这一篇文章我们接着学习PackageInsta ...

  5. Android内存管理篇 - 从updateOomAdjLocked看lowmemorykiller之外的Android进程回收机制

    提起android的进程回收机制,大家所熟知的是Android的lowmemroykiller的机制.当系统可用内存低于某个阀值时,即会杀死这个阀值对应的Adj值的所有应用.但是本篇文章并为是要介绍L ...

  6. Android 进程通信机制之 AIDL

    什么是 AIDL AIDL 全称 Android Interface Definition Language,即 安卓接口描述语言.听起来很深奥,其实它的本质就是生成进程间通信接口的辅助工具.它的存在 ...

  7. Android包管理机制(一) PackageInstaller的初始化

    前言 包管理机制是Android中的重要机制,是应用开发和系统开发需要掌握的知识点之一. 包指的是Apk.jar和so文件等等,它们被加载到Android内存中,由一个包转变成可执行的代码,这就需要一 ...

  8. Android进程回收机制LMK(Low Memory Killer)

    熟悉Android系统的童鞋都知道,系统出于体验和性能上的考虑,app在退到后台时系统并不会真正的kill掉这个进程,而是将其缓存起来.打开的应用越多,后台缓存的进程也越多.在系统内存不足的情况下,系 ...

  9. 初探Linux进程管理机制

    转至:http://ixdba.blog.51cto.com/2895551/543737 一 .进程的概念和分类1.进程的概念 Linux是一个多用户多任务的操作系统.多用户是指多个用户可以在同一时 ...

随机推荐

  1. kubeadm join 超时报错 error execution phase kubelet-start: error uploading crisocket: timed out waiting for the condition

    解决: swapoff -a kubeadm reset systemctl daemon-reload systemctl restart kubelet iptables -F && ...

  2. socket实现ftp上传下载

    socket实现ftp文件的上传和下载 server端代码: import socket import json import struct import os soc = socket.socket ...

  3. 使用 SecureRandom 产生随机数采坑记录

    公众号「码海」欢迎关注 背景 我们的项目工程里经常在每个函数需要用到 Random 的地方定义一下 Random 变量(如下) public void doSomethingCommon() { Ra ...

  4. 华为云OCR文字识别 免费在线体验!

    嘿,华为云OCR文字识别了解一下,免费在线体验! 物流行业快速提取运单信息.医疗/保险行业单据快速录入.政务办事人证检验,你知道这些都是如何实现的么? 答案就是:OCR文字识别! 作为AI时代效率倍增 ...

  5. list tuple dict 方法

    >>> dir(list)['__add__', '__class__', '__contains__', '__delattr__', '__delitem__', '__dir_ ...

  6. luogu P1102 A-B 数对 |二分查找

    题目描述 出题是一件痛苦的事情! 题目看多了也有审美疲劳,于是我舍弃了大家所熟悉的 A+B Problem,改用 A-B 了哈哈! 好吧,题目是这样的:给出一串数以及一个数字 C,要求计算出所有 A- ...

  7. luogu P2812 校园网络【[USACO]Network of Schools加强版】|Tarjan

    题目背景 浙江省的几所OI强校的神犇发明了一种人工智能,可以AC任何题目,所以他们决定建立一个网络来共享这个软件.但是由于他们脑力劳动过多导致全身无力身体被♂掏♂空,他们来找你帮助他们. 题目描述 共 ...

  8. python数据挖掘第二篇-爬虫

    python爬虫 urllib用法 eg1: from urllib import request data = request.urlopen(urlString).read() # data获取的 ...

  9. 利用Mitmproxy抓包

    http://mrpeak.cn/blog/mitmproxy/   和Charles同样强大的免费抓包软件. 它是在终端操作的,界面没有Charles那么可视化.不过也很好用,通过各种快捷键操作,效 ...

  10. 数据库Oracle数字函数

    数字函数不多: ROUND(arg1):四舍五入保留整数. arg1:数字类型.原数字. arg2:整数类型.小数点保留的位数. SQL> select round(1256.564,2) fr ...