性能工具专题
性能优化不是“凭感觉改几行代码”,而是先观测、再定位、再验证。工具章节的面试重点是:每个工具看什么、适合什么问题、输出如何转化为工程动作。
一、工具选型总览
| 问题类型 | 首选工具 | 看到什么 | 常见动作 |
|---|---|---|---|
| 启动慢 | Android Studio Profiler / Perfetto / Macrobenchmark | CPU、主线程、启动阶段耗时 | 延迟初始化、异步化、Baseline Profile |
| 卡顿掉帧 | Perfetto / Systrace / gfxinfo | Choreographer、RenderThread、帧耗时 | 减少主线程阻塞、优化布局/绘制 |
| 内存泄漏 | LeakCanary / Memory Profiler / meminfo | 引用链、堆大小、PSS | 解除生命周期引用、缓存上限 |
| I/O/网络违规 | StrictMode / Trace sections | 主线程磁盘/网络、慢调用 | 切线程、缓存、预加载 |
| Native 热点 | simpleperf / Perfetto | CPU sample、调用栈、符号 | 优化算法、减少 JNI 往返 |
| 线上复现困难 | dumpsys / bugreport / 自定义 trace | 系统状态快照 | 关联日志、设备维度排查 |
工具回答要避免“列名词”,而要说清楚“我怀疑什么 → 用什么采样 → 看哪个指标 → 怎么验证改动”。
二、Android Studio Profiler
Android Studio Profiler 适合本地开发阶段快速观察 CPU、Memory、Network、Energy。
- CPU Profiler:看主线程是否有长任务、方法调用耗时、线程调度。可用 Sampled/Instrumented/Java/Kotlin Method Trace,采样开销更低,插桩更细但扰动更大。
- Memory Profiler:看 Java/Kotlin 堆、对象分配、GC 频率、Heap Dump。适合发现短时间内对象抖动和明显泄漏。
- Network Profiler:看请求时序、流量大小、频率,但复杂线上网络问题仍要配合 OkHttp event listener、服务端日志和抓包合规流程。
- Energy Profiler:关注 wakelock、定位、网络等耗电行为。
局限:Profiler 连接调试进程会带来观测扰动,结论要用 release-like 包、Macrobenchmark 或 Perfetto 再验证。
三、Perfetto、Systrace 与 Trace sections
Perfetto 是现代 Android 系统级 tracing 工具,可观察 CPU 调度、Binder、线程状态、Choreographer、SurfaceFlinger、RenderThread、I/O 等。Systrace 是旧工具链,很多概念仍沿用,但新项目优先用 Perfetto。
import androidx.tracing.Trace
fun bindFeed(items: List<Item>) {
Trace.beginSection("Feed.bind")
try {
adapter.submitList(items)
} finally {
Trace.endSection()
}
}
Trace sections 的价值是把业务阶段写进系统 trace,让你在 Perfetto 里看到“哪段业务代码”对应主线程长任务。命名要稳定、短、能定位模块,避免把用户敏感信息写入 trace 名称。
看 Perfetto 的常见路径:
- 先看主线程是否 Running 太久或频繁 Blocked。
- 看耗时段是否跨过 VSync 导致 missed frame。
- 看 RenderThread/GPU 是否被复杂绘制或纹理上传拖慢。
- 看 Binder、I/O、锁等待是否阻塞主线程。
- 结合自定义 Trace sections 还原业务阶段。
四、Macrobenchmark 与 Baseline Profile
Macrobenchmark 用独立测试 APK 驱动目标 App,在接近真实环境下测启动、滚动、页面跳转等宏观性能。它适合做性能回归门禁,比普通单元测试更贴近用户体验。
@Test
fun startup() = benchmarkRule.measureRepeated(
packageName = "com.example.app",
metrics = listOf(StartupTimingMetric()),
iterations = 10,
startupMode = StartupMode.COLD
) {
pressHome()
startActivityAndWait()
}
Baseline Profile 是把关键路径的类和方法提前提供给 ART,安装后可更早编译热点代码,改善冷启动和首帧性能。典型流程是用 profileinstaller + baseline-prof Gradle 插件生成/合并 profile,再用 Macrobenchmark 验证收益。
面试要点:
- Macrobenchmark 关注稳定设备、固定版本、足够迭代次数和噪声控制。
- Baseline Profile 不是万能优化,主要改善解释执行/JIT 预热带来的启动和关键路径抖动。
- 性能数据要保存历史趋势,否则无法判断回归。
五、LeakCanary 与内存定位
LeakCanary 自动观察 Activity、Fragment、ViewModel 等对象生命周期,对象应被回收却仍被引用时触发 heap dump 并给出泄漏引用链。
常见泄漏原因:
- 静态单例持有 Activity/Context。
- Handler/Runnable/Coroutine 未随生命周期取消。
- Adapter、Listener、Callback 未解绑。
- Dialog/PopupWindow/Animator 持有 View。
- 全局缓存无上限或 key/value 持有页面对象。
Memory Profiler 更适合看对象分配和堆变化,LeakCanary 更适合自动发现泄漏。线上内存问题则要结合 OOM 日志、dumpsys meminfo、业务埋点和设备分布分析。
六、StrictMode 与开发期红线
StrictMode 用来在开发/测试阶段发现主线程磁盘 I/O、网络、资源未关闭、Activity 泄漏等问题。
if (BuildConfig.DEBUG) {
StrictMode.setThreadPolicy(
StrictMode.ThreadPolicy.Builder()
.detectDiskReads()
.detectDiskWrites()
.detectNetwork()
.penaltyLog()
.build()
)
}
它不是线上性能监控方案,而是把“本不该发生的开发期违规”尽早暴露。不要为了消除告警简单 permitAll,应该定位调用链并把 I/O 移到合适线程或启动阶段之外。
七、dumpsys、gfxinfo、meminfo
dumpsys 是 Android 系统服务状态入口,适合连接真机后快速拿到系统级快照。
| 命令 | 关注点 | 用法场景 |
|---|---|---|
adb shell dumpsys gfxinfo <pkg> | 帧耗时、Janky frames、渲染统计 | 页面滑动/动画掉帧 |
adb shell dumpsys meminfo <pkg> | PSS、Java/Native/Graphics 内存 | OOM、内存增长 |
adb shell dumpsys activity <pkg> | Activity/Service/进程状态 | 生命周期、进程保活排查 |
adb shell dumpsys batterystats | 耗电归因 | 后台任务、网络、唤醒 |
gfxinfo framestats 可导出每帧各阶段时间,适合脚本化对比优化前后。meminfo 的 PSS 更接近进程实际占用视角,但仍要结合 Android 版本、厂商和图形内存差异理解。
八、simpleperf 与 Native CPU 热点
simpleperf 是 Android 官方 native profiling 工具,可采样 CPU 指令、调用栈和符号,适合 NDK/JNI、音视频、加解密、图像处理等热点定位。
典型关注:
- native 函数是否占用异常 CPU。
- JNI 往返是否过多。
- 锁竞争、内存拷贝、算法复杂度是否是瓶颈。
- so 是否保留符号或能通过符号表/映射文件还原调用栈。
面试表达可以说:Java/Kotlin 层先用 Perfetto/Profiler 定位到 native 调用段,再用 simpleperf 下钻 native 热点,最后用基准测试和真实场景回归验证。
高频面试题
Q1:Profiler、Perfetto、Systrace 怎么选? Profiler 适合开发期快速看单进程 CPU/内存/网络;Perfetto 适合系统级时序分析,能看调度、渲染、Binder、I/O;Systrace 是旧链路但概念相通。复杂卡顿优先 Perfetto,内存泄漏优先 LeakCanary/Memory Profiler。
Q2:Trace.beginSection 有什么价值? 它把业务阶段标记进系统 trace,让 Perfetto 里能把主线程长任务和具体模块对应起来。注意 section 名称要稳定、简洁、无敏感信息,并保证 begin/end 成对。
Q3:Macrobenchmark 和普通 benchmark 区别? Macrobenchmark 从 App 外部驱动真实启动、滚动、跳转等宏观场景,更贴近用户体验;普通 microbenchmark 更适合测小函数/算法。性能门禁通常用 Macrobenchmark 看趋势和回归。
Q4:Baseline Profile 解决什么问题? 它把启动和关键路径热点提前提供给 ART 编译,减少冷启动/首帧阶段解释执行和 JIT 预热成本。它不是替代业务优化,仍要用 Macrobenchmark 验证收益。
Q5:LeakCanary 报出泄漏后怎么处理? 先看泄漏对象和引用链,判断是否生命周期结束后仍被持有;再定位静态引用、回调、协程、Handler、Adapter 等持有者;修复后重新进入/退出页面并确认泄漏不再出现。
易错点 / 追问
- 不要只贴工具截图,要能说明指标含义和下一步工程动作。
- 不要在 debug、插桩、连接 Profiler 的环境下直接宣称线上性能收益。
- Perfetto 看到主线程长任务后,要继续区分 CPU 忙、锁等待、I/O、Binder 等原因。
- Baseline Profile 需要随关键路径变化更新,否则 profile 会逐渐失效。
- StrictMode 告警不能靠关闭规则解决,应修正线程和资源使用。