android java进程管理(七)之进程状态和adj值

本文详细介绍了Android系统中的进程状态及adj值的作用与重要性判断标准,并解释了不同状态和adj值所代表的意义,有助于理解进程管理和内存回收机制。
部署运行你感兴趣的模型镜像

进程的状态和adj值用来定义进程的重要性,如何体现这种重要性?我们知道进程是用来运行组件的,所以组件的重要性就相当于进程的重要性,进程状态和adj值需要以组件的状态为核心来理解。

进程状态

android系统定义的进程状态很简单,仅仅是简单描述一下组件的运行信息

状态描述:
1.PROCESS_STATE_NONEXISTENT:进程运行实体还不存在
2.PROCESS_STATE_PERSISTENT:常驻内存进程
3.PROCESS_STATE_PERSISTENT_UI:常驻内存进程并且有UI显示
4.PROCESS_STATE_TOP:顶端进程,包含顶端activity
5.PROCESS_STATE_BOUND_FOREGROUND_SERVICE:系统绑定了本进程的一个Service组件
6.PROCESS_STATE_FOREGROUND_SERVICE:进程正在运行前台Service组件
7.PROCESS_STATE_TOP_SLEEPING:顶端进程,手机处于锁屏状态
8.PROCESS_STATE_IMPORTANT_FOREGROUND:前台重要进程
9.PROCESS_STATE_IMPORTANT_BACKGROUND:后台重要进程
10.PROCESS_STATE_BACKUP:正在执行备份还原的进程
11.PROCESS_STATE_HEAVY_WEIGHT:重量级进程
12.PROCESS_STATE_SERVICE:进程正在运行Service组件
13.PROCESS_STATE_RECEIVER:进程正在运行广播接收器
14.PROCESS_STATE_HOME:home进程
15.PROCESS_STATE_LAST_ACTIVITY:包含上一个显示Activity的进程
16.PROCESS_STATE_CACHED_ACTIVITY:缓存Activity的进程
17.PROCESS_STATE_CACHED_ACTIVITY_CLIENT:这个进程持有16进程组件的客户端
18.PROCESS_STATE_CACHED_EMPTY:空进程

第1个状态不是一个完整的进程,其他的进程状态是值越小越重要,那么大家是不是有点困惑?四大组件中不是Activity最重要吗?为什么15 16 17 的进程比12 13 的进程的重要性要低呢?这里边还有一个运行的概念,运行的一定比不运行的重要,12 13 都是正在运行的Service组件和广播接收器组件,而15 16 17 仅是指存在Activity,所以12 13 的重要性要高,区分一个进程的重要性从下面几个层次来看:

  • 1.是不是常驻内存进程
  • 2.是不是处于运行的状态
  • 3.组件的重要性:Activity>Service>广播接收器

adj值

这个值是给lmk(lowmemorykiller)子系统使用的,lmk是android提供的进程内存管理的子系统,这个系统有点黑,采用直接kill进程的方式回收内存,属于相当暴力的方式,所以对adj的值计算需要小心为妙,否则进程动不动被kill就不好了,android系统定义了如下级别的adj值

adj值描述:
1.NATIVE_ADJ:本地进程的adj值,不受AMS的管理
2.SYSTEM_ADJ:system_server进程的adj值
3.PERSISTENT_PROC_ADJ:常驻内存进程的adj值
4.PERSISTENT_SERVICE_ADJ:这种进程含有一个Service组件,这个组件被系统进程或者常驻内存进程绑定了
5.FOREGROUND_APP_ADJ:前台进程
6.VISIBLE_APP_ADJ:可见进程(进程包含的Activity可见)
7.PERCEPTIBLE_APP_ADJ:用户可感受的进程,什么是可感受?看是一种感受,听也是一种感受,比如后台运行的音乐播放器就是听觉感受,它就属于这类进程
8.BACKUP_APP_ADJ:运行备份还原的进程
9.HEAVY_WEIGHT_APP_ADJ:重量级进程
10.SERVICE_ADJ:含有Service组件的进程
11.HOME_APP_ADJ:home进程
12.PREVIOUS_APP_ADJ:前一个进程
13.SERVICE_B_ADJ:B list Service
14.CACHED_APP_MIN_ADJ:缓存Activity的进程
15.CACHED_APP_MAX_ADJ:缓存Activity的进程
16.UNKNOWN_ADJ:adj值不确定的进程
17.INVALID_ADJ:无效的adj

以上是目前android系统定义的adj值,每一个进程都会赋予一个adj值,越往下进程越不重要,越容易被kill掉
大家有没有发现,adj表面上来看好像没有广播接收器的事呢?其实在第5个(FOREGROUND_APP_ADJ)adj值中都包括了,这个前台进程在这里定义的很广泛,不只是包含top Activity,而且只要进程包含运行Service组件或者正在执行广播接收器,都看作是前台进程,重要性也就很高,adj值的确定的基本准则也适用上面三条:

  • 1.是不是常驻内存进程
  • 2.是不是处于运行的状态
  • 3.组件的重要性:Activity>Service>广播接收器

更新lru容器

更新进程状态和adj值

您可能感兴趣的与本文相关的镜像

Stable-Diffusion-3.5

Stable-Diffusion-3.5

图片生成
Stable-Diffusion

Stable Diffusion 3.5 (SD 3.5) 是由 Stability AI 推出的新一代文本到图像生成模型,相比 3.0 版本,它提升了图像质量、运行速度和硬件效率

<think>我们正在讨论的是在Android9系统中通过代码获取进程的OOM调整(oom_adj)。根据引用内容,我们知道oom_adj用于表示进程的重要性,系统根据这个来决定在内存不足时杀死哪些进程。在Android系统中,每个进程的oom_adj存储在其proc文件系统下的文件中,路径为`/proc/<pid>/oom_adj`(在较新的内核中可能是`/proc/<pid>/oom_score_adj`,但为了兼容性,我们可能仍然需要查看oom_adj)。但是,请注意,从Android8.0(Oreo)开始,系统对后台进程的限制更加严格,而且访问proc文件系统可能需要权限。在Android9中,非系统应用可能无法直接访问其他进程的proc文件,因为存在权限限制。因此,我们通常只能获取自己应用的进程的oom_adj。步骤:1.获取当前进程的PID(ProcessID)。2.构建文件路径:`/proc/<pid>/oom_adj`。3.读取该文件的内容,该内容应该是一个整数。注意:由于Android的安全机制,我们不能直接读取其他应用的oom_adj,除非我们的应用具有系统权限(比如系统应用)或者root权限。以下是一个示例代码,用于获取当前进程的oom_adj:```javapublicintgetOomAdjValue(){intoomAdj=-1000;//初始化为一个不可能的intpid=android.os.Process.myPid();//获取当前进程的PIDStringpath="/proc/"+pid+"/oom_adj";Filefile=newFile(path);if(file.exists()){try(BufferedReaderbr=newBufferedReader(newFileReader(file))){Stringline=br.readLine().trim();oomAdj=Integer.parseInt(line);}catch(Exceptione){e.printStackTrace();}}returnoomAdj;}```但是,需要注意的是,从Android7.0(Nougat)开始,Google限制了应用访问其他进程的proc文件(特别是oom_adj)。因此,上述方法可能只能用于调试版本或具有系统权限的应用。对于普通应用,可能会返回空内容或抛出异常。另外,在较新的内核中,系统使用`oom_score_adj`代替了`oom_adj`,它们的关系是:`oom_score_adj=oom_adj*1000`。因此,我们也可以尝试读取`/proc/<pid>/oom_score_adj`。改进后的代码(尝试读取oom_score_adj,如果失败则读取oom_adj):```javapublicintgetOomAdjValue(){intoomAdj=-1000;//初始化为一个不可能的intpid=android.os.Process.myPid();//先尝试读取oom_score_adjStringpath="/proc/"+pid+"/oom_score_adj";Filefile=newFile(path);if(!file.exists()){//如果oom_score_adj不存在,则尝试oom_adjpath="/proc/"+pid+"/oom_adj";file=newFile(path);}if(file.exists()){try(BufferedReaderbr=newBufferedReader(newFileReader(file))){Stringline=br.readLine().trim();oomAdj=Integer.parseInt(line);//如果是oom_score_adj,我们可以将其转换为旧的oom_adj(除以1000并四舍五入),但通常不需要转换,因为oom_score_adj更常用。//但为了保持与旧系统一致,我们可以不转换,直接返回。或者根据需求调整。}catch(Exceptione){e.printStackTrace();}}returnoomAdj;}```注意:在非root设备上,普通应用只能读取自己进程的proc文件。尝试读取其他进程的proc文件会失败(权限被拒绝)。另外,在Android9及更高版本中,由于隐私安全限制,即使读取自己进程的oom_adj也可能受到限制。因此,上述代码可能无法在所有设备上工作,特别是非系统应用。如果应用是系统应用(即使用系统签名)或者运行在root设备上,那么可以读取其他进程的oom_adj。但是,在非root设备上,普通应用无法读取其他进程的oom_adj。引用[4]中提到了查询企鹅进程的oom_adj,那是通过adbshell命令在root状态下查询的,因此可以获取。总结:在普通应用中,我们只能尝试获取自己进程的oom_adj,且不一定成功。如果必须获取其他进程的oom_adj,则需要系统权限或root权限。最后,关于引用[2][3]提到的保活方法,设置persistent属性或者通过系统服务设置oom_adj,这些都需要系统权限,普通应用无法使用。因此,在编写代码时,需要明确应用的权限运行环境。相关问题:1.在Android10或更高版本中,获取进程oom_adj的方法是否有变化?2.如何通过adb命令查看进程的oom_adj?3.如何将应用设置为系统应用以获取系统权限?4.除了oom_adj,还有哪些指标可以判断进程的重要性?</think>在 Android 9 系统中获取进程的 OOM 调整(oom_adj)需要通过读取 `/proc` 文件系统实现。以下是完整的代码实现方案: ### 获取进程 oom_adj 的实现代码 ```java import android.os.Process; import java.io.BufferedReader; import java.io.FileReader; public class OomAdjUtils { /** * 获取当前进程的 oom_adj * @return oom_adj ,读取失败返回 -1000 */ public static int getCurrentProcessOomAdj() { return getProcessOomAdj(Process.myPid()); } /** * 获取指定 PID 进程的 oom_adj * @param pid 目标进程 ID * @return oom_adj ,读取失败返回 -1000 */ public static int getProcessOomAdj(int pid) { String oomAdjPath = "/proc/" + pid + "/oom_adj"; try (BufferedReader reader = new BufferedReader(new FileReader(oomAdjPath))) { String line = reader.readLine(); return Integer.parseInt(line.trim()); } catch (Exception e) { // 处理异常或权限问题 return -1000; } } } ``` ### 使用示例 ```java // 获取当前进程的 oom_adj int currentOomAdj = OomAdjUtils.getCurrentProcessOomAdj(); Log.d("OOM_ADJ", "当前进程 oom_adj: " + currentOomAdj); // 获取指定进程的 oom_adj (需知道目标 PID) int targetPid = 12345; // 替换为目标进程ID int targetOomAdj = OomAdjUtils.getProcessOomAdj(targetPid); ``` ### 关键说明 1. **权限要求**: - 普通应用**只能获取自身进程**的 oom_adj - 读取其他进程的 oom_adj 需要: ```xml <uses-permission android:name="android.permission.INTERACT_ACROSS_USERS"/> ``` 或**系统签名权限**(系统级应用) 2. **OOM 含义**: - `0`:前台进程(如用户正在交互的应用) - `1-5`:可见/服务进程 - `6-15`:后台进程 - `16`:缓存/空进程 - `-17`:不可杀进程(系统核心进程)[^3] 3. **Android 9 特殊限制**: - 从 Android 8.0 开始 Google 加强了后台限制 - 直接设置 oom_adj 的接口已被隐藏(如 `setOomAdj()`) - 系统应用可通过 `android:persistent="true"` 保持低 oom_adj[^3] ### 注意事项 1. 在非 root 设备上,普通应用只能读取自身进程的 oom_adj 2. 返回 `-1000` 表示读取失败(通常是权限问题) 3. 实际可能因系统策略动态变化(如应用进入后台时会升高) 4. 替代方案:使用 `oom_score_adj`(范围 `-1000~1000`)更精确反映优先级
评论
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符
 
红包 添加红包
表情包 插入表情
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值