admin管理员组文章数量:1558047
[ Android实战 ] 后台进程长时间占用CPU被杀?excessive cpu 495132 during 300001 dur=473068 limit=25
- 背景
- 日志分析
- 源码分析
- 为什么 CPU 占用超过 100%?
- 总结
背景
客户反馈自己写的Launcher应用在后台运行几分钟就很容易被杀。
一开始没有提供日志,第一反应是lmk把应用杀掉了,因为我们的机器内存只有1G…
但是客户应用是Launcher应用,按理来说应该没那么容易被杀。还是得通过日志才能进一步分析
日志分析
客户提供完整日志后,通过应用的日志可以直接查到 pid,再过滤 pid,即可得到应用相关的所有日志,可以找到应用被杀的地方。
08-28 16:17:01.275 845 873 I am_kill : [0,19785,xxx.xxx.xxx,600,excessive cpu 495132 during 300001 dur=473068 limit=25]
08-28 16:17:01.494 845 1825 I am_proc_died: [0,19785,xxx.xxx.xxx,600,15]
08-28 16:17:01.525 845 876 I libprocessgroup: Successfully killed process cgroup uid 10233 pid 19785 in 247ms
08-28 16:17:01.532 367 367 I Zygote : Process 19785 exited due to signal 9 (Killed)
08-28 16:17:01.626 845 867 W ActivityManager: setHasOverlayUi called on unknown pid: 19785
从字面上理解,就是应用长时间占用 CPU 导致应用被系统杀掉了。不过还是得研究下源码,确认下系统到底是如何查杀的。
源码分析
在 frameworks 下搜索 “excessive cpu” 关键字,即可在 ActivityManagerSerice.java
中看到相关逻辑。
应用查杀的逻辑很简单,就是遍历所有后台应用进程,如果在某个时间段内 CPU 使用时间超过阈值,则将该进程杀掉。
final void checkExcessivePowerUsageLocked() {
......
int i = mProcessList.mLruProcesses.size();
while (i > 0) {
i--;
ProcessRecord app = mProcessList.mLruProcesses.get(i);
if (app.setProcState >= ActivityManager.PROCESS_STATE_HOME) {
......
if (doCpuKills && uptimeSince > 0) {
......
if (((cputimeUsed*100)/uptimeSince) >= cpuLimit) {
......
app.kill("excessive cpu " + cputimeUsed + " during " + uptimeSince
+ " dur=" + checkDur + " limit=" + cpuLimit, true);
......
}
}
app.lastCpuTime = app.curCpuTime;
}
}
}
checkExcessivePowerUsageLocked
是通过 CHECK_EXCESSIVE_POWER_USE_MSG
的消息进行调用的,并且它是一个定时任务,时间间隔为 POWER_CHECK_INTERVAL
case CHECK_EXCESSIVE_POWER_USE_MSG: {
synchronized (ActivityManagerService.this) {
checkExcessivePowerUsageLocked();
removeMessages(CHECK_EXCESSIVE_POWER_USE_MSG);
Message nmsg = obtainMessage(CHECK_EXCESSIVE_POWER_USE_MSG);
sendMessageDelayed(nmsg, mConstants.POWER_CHECK_INTERVAL);
}
} break;
继续搜索,可以发现 CHECK_EXCESSIVE_POWER_USE_MSG
这个任务是在 AMS 的 finishBooting
阶段就开始的。
final void finishBooting() {
......
// Start looking for apps that are abusing wake locks.
Message nmsg = mHandler.obtainMessage(CHECK_EXCESSIVE_POWER_USE_MSG);
mHandler.sendMessageDelayed(nmsg, mConstants.POWER_CHECK_INTERVAL);
// Tell anyone interested that we are done booting!
SystemProperties.set("sys.boot_completed", "1");
......
}
任务时间间隔和阈值在 ActivityManagerConstants.java
中定义:
private static final long DEFAULT_POWER_CHECK_INTERVAL = (DEBUG_POWER_QUICK ? 1 : 5) * 60*1000; // 每5分钟检查一次
private static final int DEFAULT_POWER_CHECK_MAX_CPU_1 = 25; // 5分钟内CPU使用时间超过25%则杀掉进程
private static final int DEFAULT_POWER_CHECK_MAX_CPU_2 = 25; // 10分钟内CPU使用时间超过25%则杀掉进程
private static final int DEFAULT_POWER_CHECK_MAX_CPU_3 = 10; // 15分钟内CPU使用时间超过10%则杀掉进程
private static final int DEFAULT_POWER_CHECK_MAX_CPU_4 = 2; // 15分钟后CPU使用时间超过2%则杀掉进程
总结起来就是:系统启动后,会定时检测后台进程的 CPU 消耗情况,如果在某个时间段内超过阈值,则会将进程杀死。
为什么 CPU 占用超过 100%?
还有一个很奇怪的问题,既然是某个时间段内的 CPU 占用时间,为什么会出现 CPU 占用超过 100% 的情况?
08-28 16:17:01.275 845 873 I am_kill : [0,19785,xxx.xxx.xxx,600,excessive cpu 495132 during 300001 dur=473068 limit=25]
对应源码:cputimeUsed = 495132
,uptimeSince = 300001
,checkDur = 473068
,为什么会出现 CPU 使用时间比检测时间间隔还长的情况,难道系统有 BUG?
转念一想,其实也不难理解,Android 设备的 CPU 都是多核的,当存在多线程执行任务时,CPU 的使用时间自然可能出现 double 甚至 triple 的情况。
写一个简单的 demo,多线程执行最简单的 while 累加任务,把应用放到后台去跑,马上复现了跟客户类似的日志。
09-02 15:07:12.050 698 725 W ActivityManager: Killing 8728:com.example.test/u0a100 (adj 700): excessive cpu 650590 during 300035 dur=432717 limit=25
09-02 15:07:12.162 337 337 I Zygote : Process 8728 exited due to signal 9 (Killed)
09-02 15:07:12.171 698 719 W ActivityManager: setHasOverlayUi called on unknown pid: 8728
09-02 15:07:12.173 698 728 I libprocessgroup: Successfully killed process cgroup uid 10100 pid 8728 in 121ms
总结
分析到现在已经基本结束了。总结一下,当日志中出现 excessive cpu 导致应用被杀时,可以针对不同情况进行处理:
1、首先,大概率是客户应用自身的逻辑问题,当应用进入后台时,显然不应该长时间占用 CPU。可以关注进入后台后,应用是否在执行某些耗时任务,是否反复执行,这块逻辑能否优化?
2、如果客户应用本身无法修改,可以根据实际使用场景,评估是否应用将客户应用加到白名单中,修改也很简单,在 checkExcessivePowerUsageLocked 针对应用包名跳过检查即可。
版权声明:本文标题:[ Android实战 ] 后台进程长时间占用CPU被杀?excessive cpu 495132 during 300001 dur=473068 limit=25 内容由热心网友自发贡献,该文观点仅代表作者本人, 转载请联系作者并注明出处:https://m.elefans.com/dianzi/1727308013a1107530.html, 本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如发现本站有涉嫌抄袭侵权/违法违规的内容,一经查实,本站将立刻删除。
发表评论