ARTICLE DETAIL

资讯详情

深耕网站视觉设计与运营推广的一线实战洞察。

systrace 卡顿排查实战:从时间线到根因定位

systrace 卡顿排查实战:从时间线到根因定位 排查卡顿问题的时候光靠肉眼看界面抖动、再凭感觉在代码里加日志效率其实非常低。我第一次用 Android 性能分析工具 systrace 解决线上问题最大的感受是它把“卡一下”从一种模糊的体感变成了一条带精确时间戳的事件时间轴——哪根线程在跑、跑了多久、中间被谁打断了、CPU 当时在什么频率上全部对得清清楚楚。从那以后systrace 成了我排查 Android 掉帧、启动慢、触控延迟等问题的第一站。这篇文章不讲花架子直接从底层原理、环境准备、命令行抓取、trace 界面分析、常见瓶颈图谱到完整真实案例排查链路一步步把它讲透。无论你是刚接触 Android 性能优化的新手还是已经在用 Profile 但没系统性梳理过 systrace 的进阶开发者都可以拿着这篇文章直接上手实操。1. 先搞清楚 systrace 到底在干嘛它不只是“抓日志”很多开发者在第一次接触 systrace 时容易误解它以为它像 Logcat 一样只是把系统日志按时间打印出来。实际上systrace 更像一辆装在系统里的“行车记录仪”在你指定的时间窗口内它会把所有 CPU 核心上的调度情况、每个线程的运行状态、进程间的 Binder 通信、VSYNC 信号、渲染管线流程、系统服务调用等全部以事件切片的形式记录在一个 trace 文件里。之后你就能在时间轴上放大任意一个瞬间精确看到当时发生了什么。所以它的核心价值不是“记录日志”而是把系统里那些平时看不见的协作过程变成一条宏观与微观兼顾的时间线。比如列表滑动掉帧你不仅要看 UI 线程是否卡在某个重布局上还要看是不是 RenderThread 在等 GPU 完成同步、是不是主线程在等某个 Binder 返回、是不是当时 CPU 正好被别的进程占满导致调度延迟。这些信息散落在不同模块里只有 systrace 能把它们全部拉到同一根时间轴上一齐看。1.1 为什么会卡顿性能分析的本质是找“时间去哪了”Android 视觉流畅的关键是每帧必须在 16.6ms60Hz 刷新率内完成。一旦超过这个时间系统就会跳过一帧表现就是卡顿。90Hz 屏幕对应 11.1ms120Hz 屏幕对应 8.3ms设备刷新率越高单帧预算越紧。但麻烦的是超过预算的时间不一定都消耗在你写的业务代码里。它有可能是 App 主线程里一个很长的 for 循环有可能是布局系统在重复测量一个深层嵌套的 LinearLayout也有可能是线程处于 Runnable 状态却迟迟拿不到 CPU——也就是调度延迟。更隐蔽的一种情况是主线程跑去等一个系统服务而系统服务当时忙得不可开交你代码里看的那个调用点本身可能只有一行真正的时间黑洞在另一个进程里。这就是我要强调的观点性能分析的本质不是找“哪段代码慢”而是找“时间被谁在什么时候吃掉了”。而 systrace 提供的数据结构正好就是为回答这个问题设计的——每个事件都有开始时间、结束时间、所属线程、具体类型你在时间轴上框选卡顿区域所有相关模块的细节都会同步呈现。1.2 systrace 的底层原理ftrace、atrace 与 trace eventsystrace 能记录这么多信息底层依赖的是 Linux 内核的 ftrace 机制。ftrace 是内核提供的一套追踪框架可以挂载各种事件点比如线程调度事件 sched_switch、CPU 频率变化、中断处理等。systrace 通过 ftrace 拿到内核层面的原始事件再配合设备上的 atrace 服务收集用户空间打点。atrace 的作用是从上层收集那些由系统或 App 主动标记的 trace event。比如你在代码里用Trace.beginSection(loadUserList)打了一个标记开启 app tag 抓 trace 后这个名字就会出现在主线程时间线上。系统框架层也会在很多关键路径上自动打点比如 View.measure、View.draw、Choreographer 的帧调度、SurfaceFlinger 的合成过程等。明白了这套机制你就能理解为什么 systrace 特别擅长跨层定位它把内核的调度事件、系统框架的事件、App 自定义的事件全部汇总成一个按时间排序的数据流。这有点像把行车记录仪、车内监控、GPS 轨迹全部合成到一个画面上回放任何一个环节异常都能看到它和其他环节在时间上的因果关系。1.3 和 Android Studio Profiler、Perfetto 是什么关系很多人有疑问Android Studio 里不是有 CPU Profiler 吗为什么还要单独学 systrace其实它们不是替代关系systrace 是通用型、命令行友好、面向系统级整体分析的工具CPU Profiler 是 Android Studio 内置的可视化前端更侧重于函数级采样和方法耗时分析。而 Perfetto 是 systrace 的下一代演进版数据格式更丰富UI 能力更强Android 10 之后官方强烈推荐新项目优先使用 Perfetto。systrace 的老脚本在新系统上兼容性越来越差但这个工具背后沉淀下来的分析思路——看帧、看线程状态、看调度、看 Binder一点都没有过时。学会了以 systrace 为代表的时间线事件分析方法你上手 Perfetto 也就是换一个界面的事。2. 新老工具线并存systrace、Perfetto 和 atrace 到底怎么选刚接触性能分析的人经常被工具链搞晕有人让你用 systrace.py有人说用 atrace还有人说直接上 Perfetto到底该用哪个我的建议是不要纠结“谁更好”而是先搞清楚自己手上的设备和 Android 版本再决定用哪条命令。2.1 不同系统版本下工具的变化在 Android 9 及之前的时代systrace.py 是绝对的主流一条python systrace.py命令就能生成一个 trace.html 文件用 Chrome 打开就能看。Android 10 开始Google 主推 Perfetto新的 trace 格式以.perfetto-trace为主分析界面也搬到了 web 版 Perfetto UI。Android 11 之后SDK 里的 systrace 脚本虽然还能找到但官方已经明确把它标记为 legacy新设备、新系统下跑起来经常遇到各种兼容问题。老设备、老项目上systrace 依然很能打新设备新项目上建议直接用 atrace 或 Perfetto后面我会给出具体可执行的替代方案。核心原因是systrace 的 HTML 界面基于老式 Trace Viewer面对新系统上越来越细化的 trace 事件渲染能力和可读性都跟不上。但它的分析方法论没有变所以本文后面的分析思路对两类工具都适用。2.2 Systrace / atrace / Perfetto 三者对比维度systrace.pyatrace 命令行Perfetto数据来源ftrace atraceftrace atraceftrace atrace 更多自定义数据源典型输出trace.html.atrace 文本/压缩包.perfetto-trace 二进制分析界面老式 Chrome Trace Viewer通常导入 Perfetto UIPerfetto UI系统兼容性老版本稳定新版本越来越差几乎全版本可用Android 10 推荐适合场景老项目、快速验证、理解核心概念新老设备通用命令行可控复杂性能问题、跨进程深度分析一句话总结如果只是要快速抓一次看看systrace.py 或 atrace 都行如果要做深度分析建议 Perfetto而 atrace 是兜底方案几乎任何一台开启 USB 调试的 Android 设备都能用不依赖本地 Python 环境。2.3 我建议的日常组合在实际工作中我的习惯是快速定位 UI 掉帧、启动慢、触控延迟这类问题优先用 systrace.py 或 atrace 抓系统级关键事件大概 5 到 10 秒抓完拖进 Perfetto UI 或老版 Trace Viewer 看时间线需要看具体函数耗时、定位到代码行时用 Android Studio CPU Profiler 做方法级采样或者用 Perfetto 的 CPU sampling 数据源需要长时间统计帧率、掉帧率时用dumpsys gfxinfo这类统计工具而不是一直拉着 systrace 录屏。这套组合的核心原则是先通过 systrace 类工具明确问题发生在哪个进程、哪个线程、哪个时间段再决定是否需要到函数级深挖。不要一开始就扎进方法级 profiler 里否则很容易只见树木不见森林。3. 环境准备这些坑你在第一次抓 trace 前一定会踩工欲善其事必先利其器但 systrace 的环境准备在网上的教程里往往只被一句话带过。实际上这里面的坑不少尤其是 Python 2 的兼容问题足以让一个新人在第一步就卡住。3.1 下载 platform-tools 并确认 adb 可用systrace 不依赖 Android Studio 图形界面你只需要一套 platform-tools。下载后把目录加到 PATH 环境变量里确保执行adb devices能正常看到设备。这里顺便说一句如果你在网上看到教程让你先装 Android Studio、再汉化、再去 IDE 里找 CPU Profiler 按钮那是另一条路systrace 走的是命令行跟 IDE 汉不汉化没有任何关系。设备端需要开启开发者选项和 USB 调试。连接后最好先执行adb devices确认状态是 device而不是 unauthorized。如果显示 unauthorized需要在手机上点一下“允许 USB 调试”的弹窗。这一层没通过后面所有命令都会报 no devices。3.2 Python 2 兼容问题最容易卡壳的地方老版 systrace.py 依赖 Python 2而新版操作系统默认基本都只有 Python 3。如果你直接执行python systrace.py大概率会看到一堆语法错误或者提示找不到模块。解决思路有两个一是装一个 Python 2 环境比如用 pyenv 或系统包管理器然后显式调用python2 systrace.py二是绕开 systrace.py直接用adb shell atrace抓取原始数据再导入 Perfetto UI。我个人更推荐后者少一套环境依赖数据可视化效果还更好。后文第 8 节会给具体命令。从另一个角度来说Windows 用户尤其容易栽在这里因为 Windows 上老版 systrace.py 对 Python 2 的路径处理比较敏感。如果你非要在 Windows 上用 systrace.py可以装一个 Python 2.7并把C:\Python27加入 PATH然后在命令行里用python而不是py来调用。3.3 连接设备的正确姿势USB 优先无线调试注意稳定性USB 有线连接永远是最稳的尤其是抓 trace 这种依赖系统事件采集的场景。无线 adb 虽然方便但 Wi-Fi 环境下的调度、延迟和带宽波动会影响一部分 trace 事件的准确性而且手机息屏或电量优化触发时adb 连接很容易断开。如果你实在要用无线调试比如手机频繁插拔 USB 不方便建议抓 trace 时保持设备亮屏并接入充电器通过adb pair配对后使用adb connect ip:port连接。多台设备同时连接时记得在执行 systrace 命令时用adb devices查看序列号并通过-e 序列号参数指定目标设备不然你辛辛苦苦抓了半天可能数据根本不是你想要的那台设备上的。4. 命令行抓取参数不熟会浪费半天时间准备环境只是开始真正决定 trace 质量的是命令参数。很多新手第一次用 systrace 抓出来的数据要么太短、要么 buffer 溢出、要么没有包含关键 tag白跑一趟。下面直接给出一套我常用的命令模板再把每个参数讲透。4.1 最常用的一组命令python systrace.py -t 10 -a com.example.app -b 4096 -o /tmp/mytrace.html \ gfx input view wm am app sched freq idle如果你是老 SDK 且系统兼容python换成python2如果你走 atrace 路线对应命令是adb shell atrace --async_start -t 10 -b 4096 gfx input view wm am app sched freq idle # 操作你的 App adb shell atrace --async_stop -z -o /sdcard/trace.atrace adb pull /sdcard/trace.atrace ./trace.atrace然后打开 ui.perfetto.dev把 atrace 文件拖进去即可。这条命令在几乎任何版本 Android 上都能跑我强烈建议你把它当成备胎中的主力。4.2 参数详解-t、-a、-b、-o、-e-t 持续时间。单位是秒。抓太短可能错过要复现的问题抓太长又会占用大量 buffer建议先定 10 秒。如果问题需要复杂操作才能复现可以适当增加到 30 秒但 buffer 也要同步加大。-a 指定 App 包名。这个参数会让系统额外收集该 App 进程内自定义的 trace section。支持多个包名用逗号分隔例如-a com.example.app,com.example.lib。如果你不指定trace 里依然有系统框架事件但你 App 自己代码里的打点信息会少很多。-b buffer 大小。单位是 KB默认值一般是 2048KB。10 秒的 trace 搭配 2048KB 往往够用但如果你开了很多 tag或者系统事件特别密集很容易出现 buffer overflow提示你增加 buffer 或缩短时间。我一般抓 10 秒用 4096KB抓 30 秒用 8192KB 或 16384KB。-o 输出文件路径。老版 systrace 生成的是 HTML直接用 Chrome 打开atrace 生成的是原始文本或压缩包需要导入 Perfetto UI。-e 指定设备序列号。多设备场景下必备。平时只有一台设备时可以省略。4.3 tag 的选择不是越多越好systrace 支持很多 tag可以用python systrace.py --list-tags查看当前设备支持的完整列表。但实际抓取时不要为了追求“全”把所有 tag 都打开因为 tag 越多单事件数据量越大buffer 消耗越快反而容易把关键事件冲刷掉。针对不同问题的 tag 组合可以参考下表问题类型推荐 tag 组合UI 掉帧、列表卡顿gfx input view wm am app主线程耗时定位gfx view app调度延迟、CPU 频率问题sched freq idleBinder 通信问题binder_driver binder_lock sched app系统启动、AMS/WMS 问题am wm binder_driver sched freq日常排查 UI 卡顿最稳的组合是gfx input view wm am app sched freq idle。这里面的 gfx 能看到渲染管线input 能看到输入分发view 能看到 View 的 measure/layout/drawsched 和 freq 能看到线程调度和 CPU 频率基本覆盖了“主线程、渲染线程、系统调度”三条主线。4.4 抓取时机的把控先启动 trace再操作 App一个很实际的问题trace 是有时间窗口的你怎么保证 App 的关键操作刚好发生在窗口内最好的方式是先敲下命令启动 trace然后立刻操作 App。如果用 systrace.py命令是同步阻塞的它会等待设定的时间到后自动结束期间你去复现问题即可。为了减少人工同步误差我建议先用 adb 发一条自动化命令辅助操作比如adb shell input swipe 300 1200 300 400 100让列表自动滑动可以在 trace 启动后立即执行。自动化操作还有一个好处是每次滑动轨迹一致方便前后对照。如果你用 atrace 的 async 模式就更加灵活atrace --async_start启动后 trace 在后台持续记录等你操作完再atrace --async_stop主动停止。这种方式特别适合操作步骤较长、不确定具体什么时候会触发问题的场景。5. trace 文件到手怎么读界面操作与核心视窗trace 文件拿到手只是第一步真正难的是“读”。我见过不少同事第一次打开 trace.html屏幕上全是花花绿绿的彩色条不知道从哪看起。这里我按一套固定的分析顺序来讲照着做基本不会迷路。5.1 打开 trace.html 后先做三件事用 Chrome 打开 trace.html或者直接把 atrace 文件拖进 Perfetto UI先不要急着放大看细节。第一件事看顶部的 FPS 曲线找出掉帧发生的时间段第二件事看右侧或底部的 Alert 列表里面往往已经帮你标记了系统自己识别出的异常事件第三件事用鼠标在 FPS 曲线掉下来的位置框选一个区域把它放大到能看清单个切片事件的程度。把这三件事做完你就有了一个初步的问题定位卡顿大概发生在第几秒系统提示了哪些异常。剩下的就是顺着这条线去细看具体线程。5.2 主界面区域FPS 曲线、进程状态、CPU 频率、事件时间线systrace 的界面大概分成几大块。最上面是 FPS 曲线代表每一帧是否在预算时间内完成往下是 CPU 核心活动区域可以看到每个核心上运行了哪些线程再往下是进程与线程轨道每个进程里会展开线程线程轨道上的彩色切片就是各类事件底部通常还有 System 区域包含 SurfaceFlinger、VSYNC 等系统级事件。关键要关注的是你 App 进程对应的主线程和 RenderThread。主线程上的切片往往会标明是什么类型的操作比如Frame、measure/layout/draw、Choreographer#doFrame或者系统服务的 Binder 调用。RenderThread 上的切片则与真实渲染有关比如DrawFrame、等待 GPU 完成的片段。5.3 线程状态颜色一眼判断线程在干嘛在时间线上线程状态会显示为不同颜色。这是读 trace 时最重要的基础。颜色线程状态通常意味着绿色Running线程正在 CPU 上执行代码蓝色Runnable线程就绪但等待 CPU 调度白色Sleeping线程睡眠或等待唤醒橙色Uninterruptible Sleep线程在不可中断睡眠中常见于 I/O 阻塞举个例子如果你看到主线程在大段大段地变成蓝色说明它已经准备好了要执行但 CPU 没有及时分配给它的时间片这大概率是调度问题如果主线程是绿色但绿色切片对应的事件名称非常长说明是代码执行本身耗时如果主线程大部分是白色旁边紧跟着一个 Binder 调用事件说明它在等跨进程返回。5.4 快捷键与框选放大让操作效率翻倍systrace 界面虽老快捷键却很实用。用w放大、s缩小、a和d左右平移可以快速在时间轴上游走。按住鼠标左键拖拽可以框选一个矩形区域松开后就放大到那个区域。选中某个事件切片后按m可以标记选中事件的时间范围方便记录。Perfetto UI 的快捷键逻辑也类似但额外支持用1、2、3在 select/pan/zoom 模式间切换。不管用哪个工具我的建议是先把“框选放大”和“按线程状态颜色快速定位”练熟这是分析 trace 最核心的基本功。6. 常见性能瓶颈的 trace 特征看到什么图提示什么问题工具学会了接下来就是经验问题。同样的 trace 摆在面前有人能三分钟定位到问题有人盯半小时还是一头雾水差别就在于是否熟悉常见瓶颈在 trace 上的“样子”。下面列几类我平时最常遇到的模式。6.1 主线程长耗时绿条特别长事件名特别长主线程轨道上出现一段明显超过 16.6ms 的绿色 Running 切片切片名称通常是Frame、Choreographer#doFrame之类双击放大后还能看到内部包含 measure、layout、draw 等子事件。如果整个切片被一个Relayout或onLayout撑开多半是布局层级太深或某个自定义 View 的 onMeasure 写得太重。遇到这类问题下一步是在代码里加 Trace 打点把业务具体耗时的函数精确框出来。比如在某个 onBindViewHolder 里加Trace.beginSection(bindView); // 具体逻辑 Trace.endSection();然后重新抓 trace就能看到主线程时间线上多出 bindView 这个切片进而判断耗时是不是集中在图片加载、数据解析或者某段同步 I/O 上。6.2 线程状态被调度打断蓝色 Runnable 很久才变绿这类问题比较隐蔽。主线程虽然已经 ready但迟迟拿不到 CPU表现为蓝色 Runnable 状态持续几十甚至上百毫秒Alert 列表里也常会出现 Scheduling delay 提示。常见原因是设备 CPU 资源被抢占可能是有其他进程在大量消耗 CPU也可能是系统把频率压得太低大小核调度策略把人应用线程扔在低频小核上。这时候要结合 CPU 频率轨道一起看如果当时频率很低再看是不是温控或省电策略导致锁频如果某个其他线程一直占着大核就看它是什么任务是否来自某个第三方 SDK 在后台疯狂做事情。6.3 Binder 等待线程白色旁边有 binder transaction 事件主线程如果大部分时间是白色 Sleeping但仔细看前后事件会发现它发起了一个 Binder 调用之后就在等返回。这类问题在代码层面往往只是一次普通方法调用但时间黑洞在别的进程。处理思路是先看 Binder 调用的目标进程是谁通常事件详情里会包含目标描述符。如果是 system_server再看它当时在处理什么请求是不是又转发到了某个慢任务如果是 App 自己的另一个进程就去看那个进程里对应的 Binder 线程是否在忙。跨进程查询类问题systrace 的跨进程时间线优势就体现出来了。6.4 渲染线程异常RenderThread 卡在等待 GPU 同步上UI 线程看起来挺正常任务很快做完但 RenderThread 那边一直没结束整体帧时间还是远超预算。这时候要看 RenderThread 的切片如果大段时间花在waitForFrameCompletion或 GPU completion 等待上要考虑是否过度绘制、纹理上传过大或者 GPU 负载太高。另一种常见表现是 SurfaceFlinger 那边出现 miss VSYNC主线程提交帧的节奏赶不上 vsync。这种情况需要看 gfx tag 相关的 Frame 事件以及 SurfaceFlinger 合成的时间点定位是 App 提交太晚还是 SurfaceFlinger 本身处理不过来。7. 一个真实卡顿案例的完整排查链路前面的知识都比较分散我们串一个案例来完整走一遍。场景是一个首页 Feed 列表滑动卡顿用户反馈偶现掉帧复现概率不算特别高大约 40% 左右。7.1 问题现象与初步猜测接到问题后我一开始也没急着抓 trace先在代码里找了一遍首页列表的 onBindViewHolder看看是不是有同步 I/O、复杂计算或者频繁创建对象。结果没有明显发现。凭直觉猜测可能是图片加载库的问题但禁用图片压缩后依然偶现掉帧。靠肉眼看代码解决不了问题于是决定抓 trace。因为问题偶现我用 atrace 的 async 模式启动持续 30 秒期间用 Swift 的脚本? 不用 adb 模拟多次滑动操作让它对列表进行反复上下滑动提高复现几率。最终拿到了一份比较完整的 trace。7.2 从 FPS 曲线和 Alert 入手先排除错误方向在 Perfetto UI 里打开 atrace 文件先看 FPS 曲线有将近 1 秒左右帧率从 60 掉到了 30 上下。点击 Alert 列表发现这一时间段出现了多条 Scheduling delay 警告而没有 Long View.draw 或 RepeatingFrame 这类明显的主线程耗时警告。这是一个非常重要的分水岭如果问题出在主线程逻辑耗时上Alert 一般会报 Long View.draw 或慢消息现在报的是 Scheduling delay说明主线程本身工作不多而是没及时拿到 CPU。我此前的“图片加载库导致主线程解码耗时”猜测基本可以排除方向转向线程调度。7.3 定位根因主线程长时间处于 Runnable 状态顺着 Scheduling delay 的提示我把时间轴放大到掉帧的那一秒找到 App 主线程的轨道。发现主线程切片确实有很多是蓝绿交替蓝色Runnable时间段明显偏长。正常情况下主线程应该在 vsync 到达时被唤醒很快变绿执行完一帧任务然后继续睡眠。现在它被唤醒了却在队列里等了很久才真正上 CPU。紧接着看 CPU 频率轨道发现当时几个大核频率被压得很低CPU 整体负载却不低。再看每个核心上正在运行的线程发现系统进程 system_server 里有多个 binder 线程在频繁唤醒占据了不少 CPU 时间。这解释了为什么主线程会拿不到 CPU系统侧的某些操作持续抢占资源影响了 App 线程的调度。顺着 system_server 的 binder 调用往下追发现源头指向 App 里集成的某个统计 SDK它在上报事件时频繁调用系统接口而且带了一条较重的跨进程任务链每次都触发系统侧不少额外工作。列表滑动时又会触发大量曝光上报两相叠加system_server 忙不过来最终连累了主线程调度。7.4 修复后的对照验证修复方案是把上报频率合并、批量延迟上报并放在设备空闲时执行避免滑动过程中高频触发。改动之后重新用同样的 atrace 参数抓了一遍同样的自动化滑动操作FPS 曲线稳定在 60Scheduling delay 明显减少主线程蓝色 Runnable 的时间片基本消失。这个案例给我最大的启发是很多掉帧问题并不在你写的页面代码里而在于你的 App 对外部系统施压压力又通过调度机制反噬到主线程上。如果不抓 systrace 类的时间线数据光靠猜代码路径可能永远都定位不到真正的元凶。8. systrace 抓不到的领域与迁移 Perfetto 的后路systrace 很强大但它也不是万能的。搞清楚它的边界能让你在正确的问题上用正确的工具避免浪费时间。8.1 四类 systrace 无能为力的问题第一类内存分配和泄漏问题。systrace 可以看到 GC 事件但看不到对象分配栈、堆内存布局。这类问题要用 Android Studio Memory Profiler 或 Perfetto 的 heap profile 数据源。第二类网络请求细节。systrace 里看不到 HTTP 请求的耗时拆分、头部信息、重试次数。需要配合网络抓包或接口日志。第三类未打点的函数内部耗时。如果问题发生在某个没有系统打点、你也没加 Trace 的普通方法里systrace 很难直接告诉你这段函数具体为什么慢。要么加打点要么用方法级 profiler 做采样。第四类同进程多线程内部的微观锁竞争。systrace 能看到线程状态被阻塞但具体是哪把锁、谁持有锁往往需要结合 Java 线程 dump 或其他竞态分析工具。8.2 不走老脚本直接抓 atrace 再导入 Perfetto UI如果你已经受够了 Python 2 和旧版 Chrome这里给一条我非常推荐的“后路”adb shell atrace --async_start -t 20 -b 8192 gfx input view wm am app sched freq idle # 操作 App adb shell atrace --async_stop -z -o /data/local/tmp/trace.atrace adb pull /data/local/tmp/trace.atrace ./trace.atrace拿到 trace.atrace 后打开 ui.perfetto.dev直接把这个文件拖进去就能在现代交互 UI 里分析。这套方案不依赖本地 Python 版本不依赖老版 Chrome数据量也比 html 模式更可控。如果系统版本支持还可以直接用 perfetto 命令行生成.perfetto-traceadb shell perfetto -o /data/misc/perfetto-traces/trace -t 10s sched freq gfx view app adb pull /data/misc/perfetto-traces/trace ./trace.perfetto-trace用 Perfetto UI 打开后你能享受到 SQL 查询、更精确的切片搜索、跨线程关联等高级能力。从 systrace 迁移到 Perfetto 的过程其实不存在什么学习成本核心还是那套“看时间线、看线程状态、看关键事件”的方法论。8.3 提升 trace 信息量的几个小技巧最后分享几个实战中很实用的小习惯在 App 关键路径上多打点。Trace.beginSection和Trace.endSection对性能开销极小但在分析时价值极大。尤其在 onBindViewHolder、onCreate、onClick 这类高频入口打点可以帮助你快速把系统事件和业务逻辑对应起来。养成抓对照 trace 的习惯。修复前抓一份修复后再抓一份保持操作路径完全一致这样对比起来最有说服力。对照时重点关注同一个事件切片的前后时长差异而不要笼统地看“好像流畅了”。注意保留原始设备信息。不同 CPU 架构、大小核配置、屏幕刷新率下trace 里的现象会差很多。分析时不要忽略设备型号能顺手记录当时的系统版本就更好了。说回我个人的使用体会systrace 教会我的并不是某一个具体的抓取命令而是一种“先量化再归因”的排错思路。再遇到卡顿我不会第一时间去翻代码而是先在时间轴上确认掉帧点、线程状态与系统事件的关系把问题精确锁定到一个极小范围后再回到代码层面去修复。这个思路在普通开发中非常实用也让后来我上手 Perfetto 时几乎没有遇到任何门槛。如果你正在被各种偶现卡顿折磨不要急着改代码先把 trace 抓起来它会告诉你真实的答案。
返回列表