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.rhkb.cn/news/112967.html

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

相关文章

Xilinx-7系列之可配置逻辑块CLB

目录 一、概览 二、CLB结构 三、Slice内部结构 3.1 SliceM结构 3.2 SliceL结构 3.3 查找表LUT 3.4 多路复用器 3.5 存储单元 3.6 进位逻辑 四、应用 4.1 分布式RAM 4.2 ROM(只读存储器) 4.3 Shift Registers&#xff08; 移位寄存器&#xff09; 4.4 存储资源容量…

储能辅助电力系统调峰的容量需求研究(matlab代码)

目录 1 主要内容 2 部分代码 3 程序结果 4 下载链接 1 主要内容 该程序参考文献《储能辅助电力系统调峰的容量需求研究》&#xff0c;是一个很常规很经典的matlab优化代码&#xff0c;主要是对火电、风电和储能等电力设备主体进行优化调度&#xff0c;在调峰能力达不到时采…

总结974

今日共计学习12h&#xff0c;日计划完成90%.今晚又把总结时间占用了&#xff0c;明天预留0.5h进行月总结吧&#xff0c;重新制定学习时间表&#xff0c;之前的已经用不了。 跟一个学府的老师聊了聊天&#xff0c;感觉聊完之后&#xff0c;本以为会心情舒畅&#xff0c;没想到反…

【Unity-Cinemachine相机】Cinemachine Brain属性详解

在Package Manager中下载Cinemachine 创建一个Virtual Camera&#xff0c;然后会发现Main Camera后面多出了个标志&#xff0c;而且属性也不能再修改了 因为绑定了CinemachineBrain&#xff0c;它会读取场景中某个虚拟相机的配置&#xff0c;并以此配置来控制相机的行为&#x…

XFTP上传文件出现:unknown error的解决方法

原因1&#xff1a;磁盘容量不够 查看上传的磁盘是否已经占满了&#xff0c;执行命令 df -h发现此时虚拟机的磁盘已经用尽&#xff08;只怪自己当初创建虚拟机时没有分配更多的磁盘&#xff09;&#xff0c;如下图所示 此外&#xff0c;由于磁盘空间用尽&#xff0c;Xftp上传…

拿来即用修改密码功能

<template><div><!-- 重置密码 --><el-dialogtitle"修改密码"v-model"state.resetPwdDialogVisible":showClose"state.firstLogin ! 1"width"550px"close"onCancel":close-on-click-modal"false&…

大数据开发要学习什么?学完又能做什么

学习大数据需要掌握什么语言基础&#xff1f; 1、Java基础 大数据框架90%以上都是使用Java开发语言&#xff0c;所以如果要学习大数据技术&#xff0c;首先要掌握Java基础语法以及JavaEE方向的相关知识。 2、MySQL数据库 这是学习大数据必须掌握的知识之一。数据的操作语言是…

lambda 表达式

C自学精简实践教程 目录(必读) 什么是lambda表达式&#xff1f; lambda表达式实际上就是一个类似函数的可以被调用的对象。 和函数一样可以使用圆括号调用。 只不过&#xff0c;这个函数可以定义在代码的任意位置。非常的灵活&#xff0c;自由。而函数不能定义在其他函数的…

智能化新十年,“全栈智能”定义行业“Copilot智能助手”

“智能化转型是未来十年中国企业穿越经济周期的利器”&#xff0c;这是联想集团执行副总裁兼中国区总裁刘军在去年联想创新科技大会上做出的判断&#xff0c;而2023年正值第四次工业革命第二个十年的开端&#xff0c;智能化是第四次工业革命的主题。2023年初&#xff0c;基于谷…

Kubernetes技术--Kubernetes架构组件以及核心概念

1.Kubernetes集群架构组件 搭建一个Kubernetes环境集群,其架构如下所示: 内容详解: Master:控制节点,指派任务、决策 Node:工作节点,实际干活的。 Master组件内容:

Maven的profiles多环境配置

一个项目通常都会有多个不同的运行环境&#xff0c;例如开发环境&#xff0c;测试环境、生产环境等。而不同环境的构建过程很可能是不同的&#xff0c;例如数据源配置、插件、以及依赖的版本等。每次将项目部署到不同的环境时&#xff0c;都需要修改相应的配置&#xff0c;这样…

合宙Air724UG LuatOS-Air LVGL API控件--曲线 (Arc)

曲线 (Arc) 曲线控件&#xff0c;也可以称为弧。因为 Arc 本身就是弧&#xff0c;弧形的意思。根据控件的样子也能推测出它的使用场景&#xff0c;一般用在加载器(就是等待界面转的圈圈)或者数值显示&#xff0c;数值调节这些场景。曲线控件分了两个部分&#xff0c;前景和背…

HTTPS安全通信和SSL Pinning

随着互联网的迅速发展&#xff0c;网络通信安全问题日益凸显。在这一背景下&#xff0c;HTTPS作为一种加密通信协议得到了广泛应用&#xff0c;以保障用户的数据隐私和信息安全。本文将介绍HTTPS的基本原理、发展历程&#xff0c;以及与之相关的中间人攻击和防护方法。 1. HTT…

五、工厂方法模式

一、什么是工厂方法模式 工厂方法模式是对简单工厂模式的进一步抽象化&#xff0c;其好处是可以使系统在不修改原来代码的情况下引进新的产品&#xff0c;即满足开闭原则。   工厂方法模式的主要角色如下。 抽象工厂&#xff08;Abstract Factory&#xff09;&#xff1a;提…

Docker 中下载各版本的 CentOS、CentOS Steam 方式

如果你跟我一样&#xff0c;想要在docker下载centos的镜像&#xff0c;但是无奈访问不了 https://hub.docker.com/&#xff0c;于是不知道有哪些tag可以下载&#xff0c;该如何办呢&#xff1f; 方法如下&#xff0c;以供参考。 访问&#xff1a;https://quay.io/repository/…

Modbus转Profinet网关在大型自动化仓储项目应用案例

在自动化仓储项目中&#xff0c;Modbus是一种常见的通信协议&#xff0c;用于连接各种设备&#xff0c;例如传感器、PLC和人机界面。然而&#xff0c;Modbus协议只支持串行通信&#xff0c;并且数据传输速度较慢。为了提高通信效率和整体系统性能&#xff0c;许多大型仓储项目选…

SQL-子查询

SQL 子查询 是指将一个SELECT查询&#xff08;子查询&#xff09;的结果用括号括起来作为另一个SQL语句的数据来源或者判断条件

C++调用Python Win10 Miniconda虚拟环境配置

目录 前言1. Win10 安装 Miniconda2. 创建虚拟环境3. 配置C调用python环境4. C调用Python带参函数5.遇到的问题6. 总结 前言 本文记录了Win10 系统下Qt 应用程序调用Python时配置Miniconda虚拟环境的过程及遇到的问题&#xff0c;通过配置Python虚拟环境&#xff0c;简化了Qt应…

C语言:递归思想及实例详解

简介&#xff1a;在计算机科学中是指一种通过重复将问题分解为同类的子问题而解决问题的方法。通过函数的自调用化繁为简。 递归可以说是编程中最神奇的一种算法。因为我们有时候可能不能完全明晰代码的运行过程&#xff0c;但是我们却知道代码可以跑出正确的结果。而当我们使…

Endnote中查看一个文献的分组的具体方法——以Endnote X8为例

Endnote中查看一个文献的分组的具体方法——以Endnote X8为例 一、问题 当Endnote中使用分类方法对文献进行分组管理后&#xff0c;有时需要重新调整该文献的分组&#xff0c;则需要找到这个文献在哪个分组中。本文阐述怎样寻找一个文献的分组的位置信息。 二、解决方法 1.选…