Android性能分析之实操

背景

在我的项目界面里有多个选择器(如下图)用于筛选发送网络请求,但是在点击选择器进行选择的过程中十分卡顿。

我就想着刚好学习一下使用Perfetto并锻炼自己性能分析的能力。因此,下面都是在我的第一人称的视角进行的分析,也是我自己如何使用Perfetto的分享。

过程

点击Android StudioProfiler,然后点击第三个System TraceSystem TraceAndroid Studio提供的Perfetto可视化分析工具,其底层就是Perfetto。下面的Start profiler task from有两种,分别是NowProcess StartProcess Start表示从应用进程启动开始计算,这个更适合研究App启动时的性能分析;Now表示的是从应用当前界面为基准,由于我研究单个页面的组件为何卡顿,不需要从启动App开始。因此,选择Now即可。

点击Start anyway后,Trace 便开始录制,此时需要你复现界面卡顿流程。录制完毕,即出现如下图界面。

首先看左边,从上往下看分别是时间轴、Lifecycle(生命周期)、Janky frames(卡顿帧)、MainThread(也可以说是UI Thread)、RenderThread,主要就看这几个。

  • 时间轴: 主要用于缩小发生卡顿的范围
  • 生命周期: 主要用于判断卡顿处于什么周期,适合与时间轴搭配缩小出现卡顿的范围,但是我没用上。
  • Janky frames: 这个最重要,Android要求60HZ下,每帧时间不超过1000ms/60,也就是16.6ms。也就是说绘制一帧的时间不超过16.6ms。如果某一帧超过了16.6ms,也就被称为Jank,也就是说Janky frames记录的是掉帧的片段。
  • MainThread: 在这里面主要是你的UI主线程,这里大部分是Compose布局、重组的业务。
  • RenderThread: 这个主要负责GPU渲染。

OK,大概的介绍就到这里,我们直接开始实操分析。

首先缩小时间轴,我录制的时候看到出现卡顿的时间是4s以后,那么就将时间轴控制在3-5秒左右

发现4s后的第一个Janky frmaes就很可疑,点击这个Janky然后按M键来将这个Janky frames高亮并居中显示。

这时候可以看右侧Analysis(如下图),发现Layout name为TX-弹出式窗口,恰好符合所描述的卡顿现象,其中Actual duration为237.86ms,远超16.6ms。

Main thread states表示这个Janky frame 里UI线程的情况,图中Running的状态为占据69.49%、Duration时长为26.31ms,这远超过正常范围。说明卡顿原因大概率在CPU处理上,比如Compose布局、重组、业务逻辑。

RenderThread states的Running时长为2.7ms,Runnable时长为221μs,这说明GPU渲染是没有问题的。

查看事件名发现Events里大量出现DrawFrames、query、syncFrameState、prepareTree、beginFrame。这些都是准备事件,因此推断点击选择框后popup首帧的窗口的准备成本很高,回到代码,找到DropdownMenu发现两点:

  1. expandedfalsetrue会触发重组
  2. options.forEach会一次性组合所有的选项

因为我们options数量多,所以点击时会一口气创建大量DropdownMenuItemText

假设:

  • 点击选择框后,expanded = true
  • Compose创建DropdownMenupopup
  • options.forEach一次性组合全部选项
  • 系统对popup window进行测量、布局、绘制、图层同步。

验证:

  • 限制选项数量
scss 复制代码
options.take(20).forEach { ... }
  • 打印数量
bash 复制代码
Log.d("SelectorDropdown", "$label options=${options.size}")

查看打印日志发现同一个下拉框会重复打印多次,说明它在重复重组,而不是只创建一次。所以这个卡顿的本质不是数据量大,而是点击触发了整棵选择器树的级联重组,再叠加DropdownMenu弹出窗口本身的首帧创建和绘制成本,就出现掉帧、卡顿现象。

解决方案:

  • 减小DropdownMenu创建PopupWindow的首帧成本

    • DropdownMenu/ExposedDropdownMenuBox改成页面内展开的Card + LazyColumn
  • 减少无意义状态触发

state.xxx.map {...}remember,避免每次重新构造选项列表

卡顿延迟从237.86ms->10.81ms

相关推荐
taocarts_bidfans2 小时前
外贸独立站系统性能优化实战:解决全球访问延迟与转化流失问题
性能优化·跨境电商·独立站·外贸独立站
六月雨滴2 小时前
Oracle 归档日志性能优化
数据库·oracle·性能优化
在繁华处2 小时前
Java从零到熟练(十):JVM基础与性能优化
java·jvm·性能优化
念越2 小时前
数据库系统概论第6版王珊版:第二章关系代数与第三章SQL期末重点整理
数据库·sql·性能优化
禅思院3 小时前
大列表性能优化 · 面试精讲 · 一
面试·职场和发展·性能优化
weixin_3077791318 小时前
面向高性能保密计算的定制 Linux 系统构建与自动部署方案
linux·安全·网络安全·性能优化·系统安全
无心水1 天前
【Harness:落地实战】19、从67%到92%:Hermes学习循环与GEPA算法如何实现AI自进化?——自进化核心引擎深度解析
人工智能·性能优化·openclaw·harness·hermes·honcho
MU在掘金916951 天前
用 AI 检测 Android 内存泄露:从 Perfetto Heap Graph 到自动化归因
性能优化
2401_878454531 天前
前端性能优化复习
前端·性能优化