Android查看每个线程CPU占用情况,以及工作内容分析

简介

Android应用开发阶段,有时候会发现应用占用CPU特别高,本文将针对这种场景提出解决方案,排查Java线程问题以及Native线程问题。

PS: 本文使用的Android Studio版本为3.1

查看CPU占用率的命令

adb shell top

使用参数:

Usage: top [ -m max_procs ] [ -n iterations ] [ -d delay ] [ -s sort_column ] [ -t ] [ -h ]
    -m num  Maximum number of processes to display. 最多显示几个进程,top会自动进行排序,比如让CPU占用率高的进程在前
    -n num  Updates to show before exiting. 刷新次数
    -d num  Seconds to wait between updates. 刷新间隔,可以输入小数即代表毫秒级间隔
    -s col  Column to sort by (cpu,vss,rss,thr). 选择以哪一项进行排序
    -t      Show threads instead of processes. 显示线程
    -h      Display this help screen.

下面是adb shell top -m 10 -t -d 2命令打印

User 62%, System 27%, IOW 0%, IRQ 4%
User 623 + Nice 15 + Sys 286 + Idle 57 + IOW 0 + IRQ 33 + SIRQ 8 = 1022

  PID   TID USER     PR  NI CPU% S     VSS     RSS PCY Thread          Proc
 4014  9996 u0_a280  20   0  18% R 2524268K 319356K  ta Thread-61       com.xxxxxx
 4014  4369 u0_a280  20   0   7% R 2524268K 319356K  ta xxxxxxxxxxxxxxx com.xxxxxx
 4014 10067 u0_a280  12  -8   5% R 2524268K 318748K  ta xxxxxxxxxxxxxxx com.xxxxxx
 1162  1620 system   20   0   3% S 2515560K 274232K  fg Binder:1162_3   system_server
 1162  2274 system   20   0   3% S 2515560K 274232K  fg Binder:1162_8   system_server
 4014  4136 u0_a280  10 -10   2% S 2524268K 319356K  ta RenderThread    com.xxxxxx
 9865  9865 shell    20   0   2% R   9108K   3112K  fg top             top
 4014  4064 u0_a280  21   1   2% S 2524268K 319356K  ta xxxxxxxxxxxxxxx com.xxxxxx
 4014  4014 u0_a280  16  -4   2% S 2523236K 319092K  ta xxxxxxxxxxxxxxx com.xxxxxx
 1162  2384 system   20   0   2% S 2515560K 274232K  fg Binder:1162_A   system_server

各列含义

PID:略
PR:在android N之前代表运行在哪个核上,在android N上代表优先级,当然可能设备厂商会进行自定义
CPU%:略
S:运行状态
#THR:线程数
VSS:Virtual Set Size  虚拟耗用内存(包含共享库占用的内存)
RSS:Resident Set Size 实际使用物理内存(包含共享库占用的内存)
PCY:调度策略优先级,SP_BACKGROUND/SP_FOREGROUND
UID:进程所有者的用户id
Thread:线程名称
Name:进程名

可以看出,CPU占用最高的是前两个,其中com.xxxxxx是我自己的应用包名。从Thread那一列可以看出Thread的名称。

PS:android 8.0以上的系统,TOP命令有所改变,但是大同小异,用adb shell top -H就行,具体可以查看帮助文档

查看线程工作

知道了具体哪个线程占用CPU高之后,再使用Android Studio的android profiler开启method record。导出结果后查看线程方法调用即可。
Android查看每个线程CPU占用情况,以及工作内容分析_第1张图片

android profiler无法导出

有时候,你发现一个线程CPU占用很高,但是,通过android profiler追踪调用栈的时候,显示下面这个结果:
No data available for the selected thread.
Android查看每个线程CPU占用情况,以及工作内容分析_第2张图片
此时,可以通过打断点debug调试,导出所有线程的调用栈,比如在主线程的一个按钮点击事件里面,打个断点,当程序跑到断点处时,调出Debug面板,点击左侧的Get thread dump按钮。
Android查看每个线程CPU占用情况,以及工作内容分析_第3张图片
点击之后,会出现所有现成的调用栈列表,找到消耗CPU高的线程,在右侧查看其调用栈
Android查看每个线程CPU占用情况,以及工作内容分析_第4张图片

如果出现上图的情况,调用栈并没有你的项目代码的时候,可以看看调用栈调用的对象有哪些,比如截图中有TimerThread类,则此时,可以把java堆内存导出来,然后找TimerTread对象,并查看其引用,看看能不能找到项目中的类对象对其的引用。

Native线程问题

如果,在profiler里能看到某一个线程CPU占用非常高,而通过上面这些方法仍然无法定位到问题,那么,可以确定,这个线程是Native层创建的,此时应该排查各个so是否有线程问题。

如何查看到native线程的问题,需要Android系统在8.0及以上,Android Studio 版本在3.1及以上。
在8.0手机上复现线程问题之后,使用Android Studio的CPU Profiler,查看native线程调用栈。
Android查看每个线程CPU占用情况,以及工作内容分析_第5张图片

关于CPU Profiler使用

大家参考Google霸霸的文档:https://developer.android.com/studio/profile/cpu-profiler

总结:
整体流程比较清晰

  1. 知道哪个线程消耗的CPU高(adb shell top命令)
  2. 尝试使用android profiler来获取线程调用栈
  3. 第2步如果不行,则采用断点调试打印所有线程调用栈的方式获取调用栈
  4. 第3步如果看不出东西,则把java堆内存导出来,查看第3步中的类对象的引用关系,最后定位到自己项目里的类对象中
  5. Native层的线程泄露,通过Java堆栈,或者Java虚拟机导出线程信息的方式是定位不到到问题的

转载请注明出处:https://blog.csdn.net/a740169405/article/details/79046211

参考:花式读取Android CPU使用率

你可能感兴趣的:(Android学习)