欢迎您访问程序员文章站本站旨在为大家提供分享程序员计算机编程知识!
您现在的位置是: 首页

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

程序员文章站 2022-06-09 16:43:35
...

简介

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占用情况,以及工作内容分析

android profiler无法导出

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

如果出现上图的情况,调用栈并没有你的项目代码的时候,可以看看调用栈调用的对象有哪些,比如截图中有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占用情况,以及工作内容分析

关于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使用率