Android-关于页面卡顿的排查工具与监测方案

作者:一碗清汤面

前言

关于卡顿这件事已经是老生常谈了,卡顿对于用户来说是敏感的,容易被用户直接感受到的。那么究其原因,卡顿该如何定义,对于卡顿的发生该如何排查问题,当线上用户卡顿时,在线下无法复现时,又如何获取信息来定位问题?

什么是卡顿

一般来说, 12FPS (每秒显示帧数)为最低标准,低于 12fps 画面基本上就不是连续的,而当大于 60FPS 时,人眼很难区分出来明显的变化,所以 60FPS 是衡量一个界面流畅程度的重要指标。但 FPS 低并不意味着卡顿发生,而卡顿发生 FPS 一定不高,而是以一段时间内的掉帧程度来衡量的。
假设按照 60FPS 来说, 一帧的时间为 1000ms/60 = 16.6667ms,如果某次掉帧严重,导致 1000ms 内 FPS 极低,那么就会造成画面卡住的现象。

卡顿排查工具

排查卡顿的工具有很多,大部分分为两种类型:
instrument:获取一段时间内所有函数的调用过程,可以通过分析这段时间内的函数调用流程,再进一步分析待优化的点。
sample:有选择性或者采用抽样的方式观察某些函数调用过程,可以通过这些有限的信息推测出流程中的可疑点,然后再继续细化分析。

1. CPU Profiler

CPU Profiler 是 Android Studio 自带的工具,可以查看 CPU、内存、网络和电池资源的使用情况。它可以以图形的形式展示执行时间、调用栈,而且信息全面包含所有线程,我们可以通过 Debug 类的方法来检测区间的代码:

Debug.startMethodTracing("xxx"); 
...
Debug.stopMethodTracing();

最终会在 sd 卡的 Android/data/packagename/files 文件夹下生成一个 xxx.trace 文件。通过 AS 解析我们可以看到这段时间内函数的调用以及耗时,帧率情况,CPU 的情况以及其他线程的情况,我们可以分析到具体的位置来调整,例如:

但是工具本身会带来很大的性能开销,所以有时无法反映真实的情况。

2. Systrace

systrace 是 Android 4.1 新增的性能分析工具, systrace 利用了 Linux 的ftrace调试工具,相当于在系统各个关键位置都添加了一些性能探针,也就是在代码里加了一些性能监控的埋点。Android 在 ftrace 的基础上封装了atrace,并增加了更多特有的探针,例如 Graphics、Activity Manager、Dalvik VM、System Server 等。 systrace 工具只能监控特定系统调用的耗时情况,它是属于 sample 类型,而且性能开销非常低。但是它不支持应用程序代码的耗时分析,所以在使用时有一些局限性。
使用方法:
systrace.py -t 10 sched gfx view wm am app webview -a com.example.android_kt_wandroid

它也可以使用代码的方式插桩到方法前后进行分析:

Trace.begainSection(name); 
...
Trace.endSection(name);

使用 systrace 工具会生成一份 .systrace 文件,我们可以在 Chrome 浏览器输入 chrome://tracing Load文件,它同样可以看 cpu,frame,thread 的一些情况:

通过右侧的 Alerts 可以提示一些掉帧的建议。

小结一下:无论使用哪种卡顿监控工具,最后我们都可以得到卡顿时的堆栈和当时 CPU 运行的一些信息。大部分的卡顿问题都比较好定位,例如主线程执行一个耗时任务、读一个非常大的文件或者是执行网络请求等。

卡顿监测方案

有些时候我们根本使不上上述几个工具,比如某用户反馈 xxx 页面 xxx 时卡的一批,等我实际去按用户所述的步骤操作时,整个流程十分流畅,所以我们是需要用户卡顿时的一些信息,比如用户的系统版本、CPU 负载、网络环境、应用数据等,脱离这个现场,我们本地难以复现,也就很难去解决问题。

1.消息队列

这种方式依赖主线程 Looper,监控每次 dispatchMessage 的执行耗时,BlockCanary 就是这样实现的

public static void loop() {...for (;;) {...// This must be in a local variable, in case a UI event sets the loggerPrinter logging = me.mLogging;if (logging != null) {logging.println(">>>>> Dispatching to " + msg.target + " " +msg.callback + ": " + msg.what);}msg.target.dispatchMessage(msg);if (logging != null) {logging.println("<<<<< Finished to " + msg.target + " " + msg.callback);}...}
}

主线程所有的任务都是在 dispatchMessage(msg) 方法中执行完成,那我们通过自定义 Printer,在 dispatchMessage(msg) 前后分别记录时间,并且在此之前通过另外一个线程通过 Thread#getStackTrace 接口,一直获取主线程执行堆栈信息并记录起来,当 dispatchMessage(msg) 超过一个阈值时,我们就通知另一个线程获取堆栈信息来做分析。

2.Choreographer

这种方式依赖 Choreographer 模块,我们知道, Android 系统每隔 16ms 发出 VSYNC 信号,来通知界面进行重绘、渲染,每一次同步的周期为 16.6ms,代表一帧的刷新频率。SDK 中包含了一个相关类,以及相关回调。理论上来说两次回调的时间周期应该在 16ms,如果超过了 16ms 我们则认为发生了卡顿,利用两次回调间的时间周期来判断是否发生卡顿。
我们可以在 Choreographer 模块注册一个 FrameCallback 监听对象,同时通过另外一条线程循环记录主线程堆栈信息,并在每次 Vsync 事件 doFrame 通知回来时,循环注册该监听对象,间接统计两次 Vsync 事件的时间间隔,当超出阈值时,取出记录的堆栈进行分析。

3.插桩

上述的两种方式都要单开一个线程记录方法堆栈会占用系统资源,其次有时会出问题,因为正在运行的函数有可能并不是真正耗时的函数。
例如:假设一次消息循环执行了三个函数,整个消息执行为 3000ms,由于函数 A (1500ms) 和函数 B (1000ms) 已经执行完毕,我们得到的函数 C (500ms) 并不耗时,因此我们需要拿到每个函数的耗时。

我们可以通过自定义 transform 在编译期拿到所有的 class 文件,通过 ASM 工具在所有的方法前后进行插桩,在运行时检测到卡顿后取出方法信息。

//插桩前
void func(){dosomething();
}//插桩后
void func(){Trace.i(x);dosomething();Trace.o(x);
}

但是也会有很多细节和优化的点:

  1. 避免方法数暴增。在函数的入口和出口应该插入相同的函数,在编译时提前给代码中每个方法分配一个独立的 ID 作为参数。
  2. 过滤简单的函数。过滤一些类似直接 return、i++ 这样的简单函数,并且支持黑名单配置。对一些调用非常频繁的函数,需要添加到黑名单中来降低整个方案对性能的损耗。
  3. 优化编译期的耗时。可以通过线程池以异步的方式插桩,结合 Future。
  4. 运行时存储方法信息的方式。将方法信息以 int 值保存,类似于 MeasureSpec 的设计。

微信的开源项目 matrix 中 Trace Canary 模块已经解决上述问题,感兴趣的可以看下源码。

总结

到此我们了解了几种卡顿监控的方法,已经可以解决我们的部分问题,其实很多时候卡顿问题并不难解决,相较解决来说,更困难的是如何快速发现这些卡顿点,以及通过更多的辅助信息找到真正的卡顿原因。

为了帮助到大家更好的全面清晰的掌握好性能优化,准备了相关的学习路线以及核心笔记(还该底层逻辑):https://qr18.cn/FVlo89

性能优化核心笔记:https://qr18.cn/FVlo89

启动优化

内存优化

UI优化

网络优化

Bitmap优化与图片压缩优化https://qr18.cn/FVlo89

多线程并发优化与数据传输效率优化

体积包优化

《Android 性能监控框架》:https://qr18.cn/FVlo89

《Android Framework学习手册》:https://qr18.cn/AQpN4J

  1. 开机Init 进程
  2. 开机启动 Zygote 进程
  3. 开机启动 SystemServer 进程
  4. Binder 驱动
  5. AMS 的启动过程
  6. PMS 的启动过程
  7. Launcher 的启动过程
  8. Android 四大组件
  9. Android 系统服务 - Input 事件的分发过程
  10. Android 底层渲染 - 屏幕刷新机制源码分析
  11. Android 源码分析实战
  12. ……

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.hqwc.cn/news/97345.html

如若内容造成侵权/违法违规/事实不符,请联系编程知识网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

宝塔面板一键部署Z-Blog博客 - 内网穿透实现公网访问

文章目录 1.前言2.网站搭建2.1. 网页下载和安装2.2.网页测试2.3.cpolar的安装和注册 3.本地网页发布3.1.Cpolar临时数据隧道3.2.Cpolar稳定隧道&#xff08;云端设置&#xff09;3.3.Cpolar稳定隧道&#xff08;本地设置&#xff09; 4.公网访问测试5.结语 1.前言 Ubuntu系统作…

ceph源码阅读 erasure-code

1、ceph纠删码 纠删码(Erasure Code)是比较流行的数据冗余的存储方法&#xff0c;将原始数据分成k个数据块(data chunk)&#xff0c;通过k个数据块计算出m个校验块(coding chunk)。把nkm个数据块保存在不同的节点&#xff0c;通过n中的任意k个块还原出原始数据。EC包含编码和解…

SpringMVC使用

文章目录 一.MVC基础概念1.MVC定义2.SpringMVC和MVC的关系 二.SpringMVC的使用1.RequestMapping2.获取参数1.获取单个参数2.传递对象3.后端参数重命名&#xff08;后端参数映射&#xff09;4.获取URL中参数PathVariable5.上传文件RequestPart6.获取Cookie/Session/header 3.返回…

Flink+Paimon多流拼接性能优化实战

目录 &#xff08;零&#xff09;本文简介 意外收获&#xff1a; &#xff08;一&#xff09;背景 &#xff08;二&#xff09;探索梳理过程 &#xff08;三&#xff09;源码改造 &#xff08;四&#xff09;修改效果 1、JOB状态 2、Level5的dataFile总大小 3、数据延…

企业网络安全:威胁情报解决方案

什么是威胁情报 威胁情报是网络安全的关键组成部分&#xff0c;可为潜在的恶意来源提供有价值的见解&#xff0c;这些知识可帮助组织主动识别和防止网络攻击&#xff0c;通过利用 STIX/TAXII 等威胁源&#xff0c;组织可以检测其网络中的潜在攻击&#xff0c;从而促进快速检测…

OJ练习第160题——LRU 缓存

LRU 缓存 力扣链接&#xff1a;146. LRU 缓存 题目描述 请你设计并实现一个满足 LRU (最近最少使用) 缓存 约束的数据结构。 实现 LRUCache 类&#xff1a; LRUCache(int capacity) 以 正整数 作为容量 capacity 初始化 LRU 缓存 int get(int key) 如果关键字 key 存在于缓…

用迅为RK3568开发板使用OpenCV处理图像颜色通道提取ROI

本小节代码在配套资料“iTOP-3568 开发板\03_【iTOP-RK3568 开发板】指南教程 \04_OpenCV 开发配套资料\07”目录下&#xff0c;如下图所示&#xff1a; 在计算机的色彩图像中存有三个通道&#xff0c;即 BGR 通道&#xff0c;根据三个颜色通道的亮度值来显示出不同的颜色&…

ubuntu22.04搭建verilator仿真环境

概述 操作系统为 Ubuntu(22.04.2 LTS)&#xff0c;本次安装verilator开源verilog仿真工具&#xff0c;进行RTL功能仿真。下面构建版本为5.008的verilator仿真环境。先看一下我系统的版本&#xff1a; 安装流程 安装依赖 sudo apt-get install git perl python3 make autoc…

Echarts遇到Vue3时遇到的问题

将vue2的Echarts代码迁移到了vue3项目上&#xff0c;引发的问题 问题描述&#xff1a; 1. 点击图例legend时刻度轴偏移&#xff0c;图像不展示&#xff0c;以及报错 初始chart正常.图 点击图例后的chart和报错.图 2. 调用resize()不生效且报错 初始正常.图 修改屏幕尺寸调用r…

ReentrantLock 原理

可以看到ReentrantLock提供了两个同步器&#xff0c;实现公平锁和非公平锁&#xff0c;都继承自AQS。 默认是非公平锁&#xff01; 下面是对ReentrantLock 的源码解析&#xff1a; 加锁源码 // Sync 继承自 AQS static final class NonfairSync extends Sync {private stati…

[C++网络协议] I/O复用

具有代表性的并发服务器端实现模型和方法&#xff1a; 多进程服务器&#xff1a;通过创建多个进程提供服务。 多路复用服务器&#xff1a;通过捆绑并统一管理I/O对象提供服务。✔ 多线程服务器&#xff1a;通过生成与客户端等量的线程提供服务。 目录 1. I/O复用 2. select函…

构建简单的Node.js HTTP服务器,发布公网远程访问的快速方法

文章目录 前言1.安装Node.js环境2.创建node.js服务3. 访问node.js 服务4.内网穿透4.1 安装配置cpolar内网穿透4.2 创建隧道映射本地端口 5.固定公网地址 前言 Node.js 是能够在服务器端运行 JavaScript 的开放源代码、跨平台运行环境。Node.js 由 OpenJS Foundation&#xff0…