Keyboard shortcuts

Press or to navigate between chapters

Press S or / to search in the book

Press ? to show this help

Press Esc to hide this help

性能工具专题

性能优化不是“凭感觉改几行代码”,而是先观测、再定位、再验证。工具章节的面试重点是:每个工具看什么、适合什么问题、输出如何转化为工程动作。

一、工具选型总览

问题类型首选工具看到什么常见动作
启动慢Android Studio Profiler / Perfetto / MacrobenchmarkCPU、主线程、启动阶段耗时延迟初始化、异步化、Baseline Profile
卡顿掉帧Perfetto / Systrace / gfxinfoChoreographer、RenderThread、帧耗时减少主线程阻塞、优化布局/绘制
内存泄漏LeakCanary / Memory Profiler / meminfo引用链、堆大小、PSS解除生命周期引用、缓存上限
I/O/网络违规StrictMode / Trace sections主线程磁盘/网络、慢调用切线程、缓存、预加载
Native 热点simpleperf / PerfettoCPU 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 的常见路径:

  1. 先看主线程是否 Running 太久或频繁 Blocked。
  2. 看耗时段是否跨过 VSync 导致 missed frame。
  3. 看 RenderThread/GPU 是否被复杂绘制或纹理上传拖慢。
  4. 看 Binder、I/O、锁等待是否阻塞主线程。
  5. 结合自定义 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 告警不能靠关闭规则解决,应修正线程和资源使用。