十年匠心定制 · 商业建站与技术教学双线并行 咨询热线:400-886-1026 service@lmnt.cn
ARTICLE DETAIL

资讯详情

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

Android性能分析:从systrace到perfetto,掌握卡顿定位核心技术

Android性能分析:从systrace到perfetto,掌握卡顿定位核心技术 1. 从“卡顿”到“真相”为什么我们需要systrace做Android开发或者性能优化的朋友肯定都遇到过这样的场景用户反馈某个页面滑动起来一顿一顿的或者点击按钮后要等一两秒才有反应。你拿到测试机复现了问题但看着满屏的代码却感觉无从下手。是主线程被阻塞了是某个IO操作太耗时还是渲染管线出了问题光靠打Log或者看CPU占用率就像隔靴搔痒很难抓到问题的“七寸”。这时候你就需要一个能透视系统内部运行状态的“显微镜”——systrace。它不是一个独立的App而是Android系统内置的一套性能分析工具集。它的核心价值在于能够以极低的开销同时记录下系统中多个核心模块如CPU调度、应用进程、SurfaceFlinger渲染、磁盘I/O等在一段时间内的关键事件。最终它会生成一个时间线Timeline视图让你能清晰地看到在发生卡顿的那几百毫秒里系统的每一个核心组件到底在干什么是谁“偷走”了本该流畅运行的时间。在Android性能分析领域systrace几乎是定位系统级、框架级性能问题的“第一选择”。它比单纯的Profiler更底层比直接看Logcat更全局比硬件性能计数器更易解读。而提到抓取systrace就绕不开两个核心工具atrace和perfetto。简单来说atrace是传统的、基于命令行的抓取工具而perfetto是Google力推的下一代、功能更强大的跨平台追踪解决方案。理解它们是你深入Android系统性能世界的必修课。2. 工具演进atrace与perfetto的前世今生要用好工具先得了解它的来龙去脉。在Android系统中负责记录这些内核及用户空间事件的底层设施是Linux内核的ftrace。你可以把它理解为一个遍布系统关键路径的“传感器网络”。而atrace和perfetto则是两套不同的“数据采集与展示系统”。2.1 atrace经典命令行工具atrace是Android早期版本中用于抓取systrace数据的主要工具。它本质上是一个封装脚本通过adb shell在设备上执行其工作流程可以概括为参数解析你通过命令行指定想要追踪的类别categories例如gfx图形、view视图系统、schedCPU调度。控制ftraceatrace会向内核的ftrace系统写入控制命令打开对应事件源的追踪开关。数据采集追踪开始后事件数据会写入内核的环形缓冲区。数据输出追踪结束时atrace从缓冲区读取数据并通过标准输出或文件的方式将数据传回主机。生成HTML主机端的Python脚本通常是systrace.py会将这些原始数据转换为可以在Chrome浏览器中打开的、交互式的HTML可视化报告。它的典型命令长这样python systrace.py gfx view sched freq -t 5 -o my_trace.html这条命令会抓取5秒钟的图形、视图和调度信息并输出到my_trace.html。atrace的核心特点与局限优点直接、轻量与旧版本Android特别是Android 4.3引入systrace到Android 9之前兼容性好是很多老教程和脚本的基础。局限功能固定能追踪的事件类别categories是预定义的扩展性差。配置复杂高级配置如特定进程过滤、自定义事件需要直接操作/sys/kernel/debug/tracing/下的文件对用户不友好。数据单一主要是内核ftrace事件对于上层App的定制化追踪支持较弱。2.2 perfetto新一代的追踪架构随着系统复杂度提升atrace的架构逐渐力不从心。Google从Android 10开始大力推广perfetto并在Android 11及更高版本中将其作为默认的追踪解决方案。perfetto不是一个简单的工具替换而是一套全新的、模块化的追踪平台。perfetto的革新之处统一的守护进程设备上有一个常驻的traced守护进程统一管理所有追踪会话的生命周期和数据流避免了atrace每次抓取都要重新配置内核的繁琐。强大的配置能力通过一个trace_config.proto文本文件你可以极其精细地控制追踪行为包括数据源ftrace,atraceevents, 自定义的Probes、采样频率、缓冲区大小、过滤条件指定进程名、线程名等。这相当于给你了一张详细的“传感器部署图”。丰富的数据源除了继承ftraceperfetto还原生支持系统属性追踪记录电池电量、CPU频率等变化。内存快照在追踪中插入系统内存状态的详细快照。Heap Profiler追踪Native内存分配/释放。自定义用户空间探测User-space probes开发者可以在自己的App中插入特定标记并在systrace图中看到它们。现代化的分析界面perfetto提供了功能强大的Web版UIui.perfetto.dev其分析能力远超旧的systrace.html视图支持SQL查询追踪数据、自定义Metrics计算等。一个直观的比喻如果atrace是一台功能固定的卡片相机那么perfetto就是一台可更换镜头、支持RAW格式、并能连接多种外置传感器的专业微单。后者为你提供了前所未有的控制力和分析深度。3. 实战指南手把手抓取你的第一份systrace理论说了这么多我们直接上手操作。下面我将分别介绍使用atrace兼容模式和perfetto两种方式抓取systrace的完整步骤并解释每一步背后的意图。3.1 方法一使用传统的atrace通过systrace.py脚本这种方式主要适用于历史项目或需要与旧流程兼容的场景。你需要准备Android SDK中的命令行工具。步骤1环境准备与连接设备确保你的开发机已安装Android SDK Platform-Tools并通过USB连接了Android设备确保adb devices能识别。在设备上打开“开发者选项”并开启“USB调试”。此外为了抓取完整的图形数据建议在开发者选项中开启“GPU呈现模式分析”并选择“在adb shell dumpsys gfxinfo中”或“选项线型图”。这一步是为了让系统记录更详细的帧时序数据。步骤2确定追踪类别Categories这是关键一步。盲目开启所有类别会导致数据量巨大分析困难。应根据你的问题域选择卡顿/流畅度分析gfx(图形),view(视图系统),sched(CPU调度),freq(CPU频率) 是核心。启动速度分析加上am(Activity Manager),wm(Window Manager)。功耗分析power,battery。磁盘I/O分析disk。 你可以使用adb shell atrace --list_categories命令查看设备支持的所有类别。步骤3执行抓取命令打开终端进入Android SDK的platform-tools/systrace目录或确保systrace.py在PATH中。执行如下命令python systrace.py gfx view sched freq -t 5 -o my_trace.htmlgfx view sched freq指定要追踪的类别。-t 5追踪时长为5秒。关键技巧在命令执行后你有大约3-5秒的时间在设备上操作复现卡顿场景例如快速滑动列表。所以时机要把握好。-o my_trace.html指定输出文件。高级参数-a package_name仅追踪指定包名的应用能极大减少干扰信息。非常实用。--buf-size缓冲区大小如果追踪时间长或事件密集可以适当调大如20480KB避免丢事件。步骤4分析结果命令执行完毕后会生成my_trace.html文件。用Chrome浏览器打开它。你会看到一个由许多水平时间线组成的界面。这里分享几个最常用的分析技巧放大与导航用W放大、S缩小、A左移、D右移来聚焦到问题发生的时间段。帧状态条最上方有一排彩色的小方块每个代表一帧。绿色表示流畅16.6ms内完成黄色或红色表示掉帧超过16.6ms。直接点击红色/黄色方块视图会自动定位到该帧。查看线程状态每个线程有一行。不同颜色代表不同状态绿色Running、蓝色Runnable、白色Sleeping。长时的蓝色块通常意味着该线程在等待CPU调度可能是CPU饱和的迹象。点击事件条点击任何一个色块如一个doFrame或Choreographer下方会显示该事件的详细信息包括耗时、所在线程等。注意从Android 10开始SDK中的systrace.py脚本实际上在底层调用了perfetto。你可以把它看作是一个兼容层。纯正的atrace命令adb shell atrace ...仍然存在但它只输出原始数据需要手动转换。3.2 方法二使用现代perfetto推荐这是当前和未来的主流方式功能更强大。有两种主要使用路径通过Web UI记录或通过命令行记录。路径A通过Perfetto Web UI可视化操作这是最简单直观的方式适合大多数场景。在Chrome浏览器中打开 ui.perfetto.dev 。点击左侧“Record new trace”。在“Recording settings”面板中你可以看到类似atrace的类别选择如Android App SysTrace但配置项更丰富。你可以直接勾选。在“Buffers”和“Data sources”部分可以展开进行高级配置例如设置缓冲区大小、添加内存信息记录等。选择“Start recording”。此时页面会给出一个adb命令。你需要在电脑终端中执行这个命令它会在设备和浏览器之间建立连接。在设备上复现问题。点击Web UI上的“Stop”结束录制追踪文件会自动下载并在浏览器中打开分析。路径B通过命令行perfetto进行高级定制当你需要自动化、或使用Web UI不支持的超复杂配置时命令行是更强大的选择。准备配置文件创建一个config.pbtx文本文件Protocol Buffer Text格式。这是perfetto的核心。一个基础的配置示例如下buffers: { size_kb: 20480 fill_policy: DISCARD } data_sources: { config { name: linux.ftrace ftrace_config { ftrace_events: sched/sched_switch ftrace_events: sched/sched_wakeup ftrace_events: irq/irq_handler_entry ftrace_events: android_fs_dataread_end atrace_categories: gfx atrace_categories: view atrace_apps: com.example.myapp } } } duration_ms: 5000这个配置定义了一个20MB的缓冲区开启了调度、中断、文件读等ftrace事件以及gfx和view类别的atrace事件并且只追踪包名为com.example.myapp的应用持续5秒。执行抓取通过adb将配置推送到设备并执行。adb push config.pbtx /data/local/tmp/ adb shell cat /data/local/tmp/config.pbtx | perfetto --txt -c - --out /data/local/tmp/trace.perfetto-trace拉取并查看结果adb pull /data/local/tmp/trace.perfetto-trace .将生成的.perfetto-trace文件拖拽到 ui.perfetto.dev 即可进行分析。命令行方式的优势在于你可以将配置文件纳入版本控制与团队共享一套标准的性能分析配置确保每次抓取的数据维度一致便于对比。4. 从数据到洞见深度解读systrace报告抓取到trace文件只是第一步从中读出问题才是核心能力。面对密密麻麻的时间线新手往往会感到迷茫。我们以一个典型的“列表滑动卡顿”问题为例拆解分析思路。4.1 分析框架自上而下逐层定位不要一开始就扎进某个线程的细节里。正确的分析路径应该是全局概览定位问题区间首先看顶部的Frames时间线找到连续出现黄色或红色帧掉帧的区域。将时间窗口放大到覆盖这几帧。观察CPU频率曲线如果开启了freq。在卡顿期间CPU频率是否被拉满如果频率很高但依然卡顿可能不是CPU算力问题而是等待如I/O或锁竞争问题。应用层分析找到“主犯”找到你的应用进程通常以包名命名。展开其主线程通常是main。在主线程的时间线上寻找长块的、颜色为绿色Running或蓝色Runnable的事件。一个帧周期约16.6ms内主线程应该快速完成doFrame中的测量、布局、绘制工作。如果出现一个持续几十毫秒的Choreographer#doFrame或者一个长时间的measure/layout/draw那它就是导致掉帧的直接原因。常见模式长耗时UI操作如复杂的onDraw、庞大的视图树遍历performTraversals。主线程I/O在时间线上看到binder调用后接续的mmc存储或block磁盘块I/O事件并且阻塞了主线程。锁等待主线程长时间处于futex_wait或monitor_wait状态说明它在等待某个锁很可能被其他线程持有。系统层关联挖掘“帮凶”如果主线程本身没有长任务但帧就是被延迟执行了需要看系统服务。查看SurfaceFlinger进程。SurfaceFlinger是合成所有窗口的组件。如果它的composeSurfaces耗时很长可能是图层太多或过于复杂。查看RenderThread应用的渲染线程。如果它的DrawFrame耗时很长可能是OpenGL指令复杂或纹理上传慢。查看binder通信。频繁的、跨进程的binder调用显示为箭头本身就有开销也可能导致等待。4.2 实战案例解码一个真实的卡顿帧假设我们分析一个卡顿帧点击该帧对应的红色方块并放大主线程时间线你可能会看到如下结构[ 主线程 Timeline ] |-- Choreographer#doFrame (id: 1234) [耗时: 32ms] -- 严重超时 |-- input (1ms) |-- animation (1ms) |-- traversal (28ms) -- 罪魁祸首在这里 |-- performMeasure (10ms) |-- performLayout (15ms) -- 布局耗时异常 |-- ViewGroup.layout()... |-- ... (展开发现某个自定义View的onLayout中有一个耗时循环) |-- performDraw (3ms) |-- commit (2ms)这个案例清晰地告诉我们掉帧的原因是performLayout耗时15ms。进一步展开我们发现是一个自定义View在onLayout中执行了低效的循环计算。修复方案就是优化该自定义View的布局逻辑避免在主线程进行重型计算。另一个常见模式I/O阻塞在主线程上你可能会看到这样的序列Binder transaction-mmc_read- 主线程长时间睡眠白色。这表示主线程发起了一个Binder调用可能是读取数据库或文件然后在等待磁盘I/O响应。解决方案就是将此类操作移至后台线程。5. 进阶技巧与避坑指南掌握了基础操作和分析方法后一些进阶技巧和常见陷阱能让你事半功倍。5.1 自定义Trace Points给你的代码打上标记systrace的强大之处在于你不仅可以看系统事件还可以注入自己的事件。这就像在时间线上埋下“路标”让你一眼就能找到关键业务逻辑的执行位置。在Java/Kotlin代码中import android.os.Trace; ... public void myBusinessMethod() { Trace.beginSection(MyBusinessLogic_LoadData); // 标记开始 try { // ... 你的耗时操作 ... } finally { Trace.endSection(); // 标记结束 } }在Native C代码中#include android/trace.h #include trace.h // 或者使用ATrace宏 ... ATRACE_BEGIN(NativeRenderFrame); // ... 渲染代码 ... ATRACE_END();编译时需链接libandroid库。添加这些标记后在systrace报告中你的应用进程下就会出现对应的色块其名称就是你传入的字符串。这对于定位大型应用中特定模块的性能问题至关重要。5.2 常见陷阱与解决方案“抓不到数据”或“数据不全”权限问题确保设备是userdebug或eng版本或者有root权限。普通用户版Android对ftrace访问有严格限制。开发时最好使用模拟器或可刷userdebug镜像的真机。缓冲区溢出如果事件非常密集例如高频的锁竞争或日志默认缓冲区可能太小导致早期事件被覆盖。解决方案是增大--buf-size参数atrace或在perfetto配置中增加buffer_size_kb。类别未启用有些追踪类别需要特定的系统属性或内核配置。使用adb shell atrace --list_categories确认所需类别是否可用。“报告打开一片空白或解析错误”确保使用Chrome浏览器打开。旧版systrace的HTML依赖Chrome的特定API。检查文件是否下载完整。perfetto的.perfetto-trace文件较大网络不好时可能损坏。如果是从命令行atrace抓取的原始数据需要用systrace.py处理成HTML而不是直接用浏览器打开文本文件。“分析时找不到关键进程或线程”在perfettoUI中利用左上角的搜索框。你可以搜索进程名、线程名、甚至是你自定义的Trace Section名称。确保抓取时指定了目标应用-a参数或atrace_apps配置。否则系统进程的噪音会很大。线程可能因为空闲而被折叠。点击进程名旁边的“”号展开所有线程。“无法确定卡顿的根本原因”结合其他工具systrace擅长定位“哪里慢了”但有时对“为什么慢”指示不足。例如发现主线程在monitor_wait你需要结合Java或Native的CPU Profiler查看此时哪些线程持有了锁。发现内存频繁回收需要结合Memory Profiler或Heap Snapshot。进行对比分析抓取一段“流畅运行”的trace和一段“卡顿”的trace在perfettoUI中左右分屏对比差异点往往就是问题所在。关注“唤醒”关系在sched调度事件中关注sched_wakeup事件。线程A唤醒线程B会在时间线上形成一个箭头。这能帮你理清线程间的依赖和等待链。5.3 自动化与持续集成对于大型项目性能回归需要持续监控。你可以将perfetto命令行工具集成到CI/CD流水线中。编写一个固定的、覆盖核心场景的trace_config.pbtx文件。在自动化测试脚本中在关键场景开始前启动perfetto录制场景结束后停止。将生成的trace文件作为产物保存。可以编写脚本使用perfetto的trace_processor命令行工具自动解析trace计算关键指标如帧率、主线程繁忙率、特定方法耗时并与基线比较超标则告警。这能将性能问题左移在代码合并前就发现潜在的性能退化而不是等到用户投诉。
返回列表