Android 常见性能问题总结

0. 使用边界

  • 版本基线:以 2026-10-20 为时间点,主线讨论 Android 17 / API 37;平台机制建议按 AOSP android-17.0.0_r1 复核,内核机制按 ACK android17-6.18-2026-06_r6 复核。
  • 来源分层:官方 Vitals/开发者文档用于定义指标和警戒线;社区反馈用于发现体验回归,不直接作为平台机制结论;提供的文档用于把现象落到源码锚点、版本边界和观测方法。
  • 阈值使用:Play/Vitals 阈值适合做告警、发版门禁和灰度回滚线,不应替代同设备、同构建、同 workload 的 A/B 测试。
  • 常见失败模式:在错误状态下测到正确现象,然后把现象优化成另一个指标。所有结论都要带设备、构建、负载、工具、样本量、分位数和对照基线。

1. 总览:官方 Vitals 与社区高频问题

Android 官方 Vitals 长期关注 ANR、崩溃、慢渲染/冻帧、卡死 WakeLock、过量唤醒、后台扫描、后台网络等质量面。社区对 Android 17 的反馈更接近"稳态迭代":一部分用户无感,一部分用户感知更快,也有小部分用户报告更慢/更卡,低 RAM 或旧机型更容易暴露后台维护和热/调度差异。

类别 典型症状 第一优先证据 最容易误判
渲染/Jank 滑动卡、动画跳、点击响应慢、高刷设备更明显 FrameTimeline/JankStats/dumpsys gfxinfo + 主线程/RenderThread/GPU/HWC 只看 doFrame;忽略 RenderThread、fence、thermal、刷新率
ANR 输入无响应、广播/服务超时、Provider 卡住 ANR trace + 组件计时窗口 + 线程状态 + Binder/I/O/GC/LMKD 主线程栈停在 nativePollOnce 就判断系统误报
启动 冷启动慢、首帧后仍不可用、升级后变慢 启动分段 timeline + pm art dump + Macrobenchmark CompilationMode 把 Splash 当优化;把热启动当冷启动;编译状态不一致
内存 PSS 增长、OOM、后台被杀、切回重建 meminfo 分域 + heap dump/heapprofd + ApplicationExitInfo RSS/PSS 混用;只看 Java heap 漏 Native/Graphics
功耗/热 发热、降频、续航差、后台频繁唤醒 batterystats/Historian + power rail + thermal headroom + wakeup 只看 CPU/FPS;把省电模式当固定参数
稳定性/退出 Crash、Native abort、WebView renderer 死、进程被杀 Crash symbol + tombstone + ApplicationExitInfo + vitals 用单一 exit reason 下结论
I/O/数据库 SP 卡、SQLite 慢、文件/媒体路径慢、OTA 后慢 Perfetto I/O/page fault + query plan + dbinfo + bugreport 增量 把 OTA/首启 dexopt、快照合并、ZRAM/mmd 归因到 App
Binder/IPC 同步调用慢、TransactionTooLarge、跨进程黑屏/超时 Binder flow + 目标线程状态 + buffer/对象图 + 线程池 把 Binder 说成一次拷贝所以快
网络 首屏慢、DNS/TLS 高、弱网重试风暴、后台偷跑 客户端阶段耗时 + 接入层对账 + network callback/Job reason 把 API 窗口当硬件窗口;只看 dnsStart/dnsEnd
版本/归因 升级后变慢、targetSdk 触发行为变化、OEM 差异 build fingerprint + targetSdk/compat change + Mainline/ART + uname/PAGE_SIZE 从 Android 大版本反推内核/HAL;48-72 小时内下结论

2. 渲染卡顿 / Jank / Frozen Frames

官方口径:慢帧通常指超过 16ms 的 UI 帧;冻帧指超过 700ms 的帧,体感接近应用卡死近一秒。高刷下预算更紧:60Hz 约 16.6ms,90Hz 约 11ms,120Hz 约 8.3ms。

  • 主线程:I/O、JSON/XML 解析、图片解码、同步 Binder、数据库/SP、大对象分配、反射/注解扫描。
  • 列表:RecyclerView onBindViewHolder 或 Compose item 组合中做解码、格式化、创建对象;keys/DiffUtil 不当导致整表重建;预取失效。
  • 绘制:View 层级深、过度绘制、onDraw 分配对象、离屏 pass 多;Compose 重组范围过大、不稳定参数、状态读错位置。
  • 系统侧:RenderThread、GPU 驱动、SurfaceFlinger、BufferQueue/fence、HWC validate/present、ARR/刷新率切换、thermal 降频。
  • 分析顺序:先用 FrameTimeline/FrameTracer 判定错过的是应用 deadline 还是显示合成 deadline;再回到主线程/RenderThread/GPU/HWC 取证。

3. ANR

常用组件超时边界:Input 约 5s;前台 BroadcastReceiver 约 10s、后台约 60s;Service 主要生命周期约 20s;Android 15+ 起 startForegroundService 后未尽快 startForeground 的时限更严格。

  • 主线程:网络、数据库、文件、SP apply 后的组件收尾/fsync、超大 JSON 解析、锁等待/死锁、同步 Binder 长事务。
  • 组件:BroadcastReceiver.onReceive 做长工作;Service/JobService/ContentProvider 初始化或 publish 慢;前台服务启动违规。
  • 跨进程:Binder 线程池耗尽、嵌套调用、锁顺序不一致、目标进程冻结/解冻等待。
  • 特殊 ANR:CPU 饥饿、I/O、GC/reclaim、LMKD、cached freezer、SQLite/WAL、InputTransport finished signal 历史缺陷。
  • 方法:ANR trace 只是入口;要联合 InputDispatcher WaitQueue、组件计时窗口、Binder flow、线程状态、锁、I/O、GC、lmkd/freezer。

4. 启动慢

常见质量线:cold start >5s、warm start >2s 应视为高优问题;中低端机 cold start 常要求压到 1.5--2s。实验室需用 Macrobenchmark 固定 CompilationMode,线上区分冷/温/热启动。

  • 关键路径:ProcessList → Zygote/USAP → PostFork → ActivityThreadMain → attachApplication → bindApplication → Provider/Application → Activity/View/Compose → first frame。
  • 高频根因:ContentProvider 早于 Application.onCreate;Jetpack Startup/广告/统计/推送 SDK 自动初始化;DI 图、数据库、序列化、路由、日志框架提前建图;首屏布局节点过多、inflate/Compose initial composition 重;大图未按显示尺寸解码。
  • 编译与产物:Baseline/Startup/Cloud Profile 覆盖不足;R8 与 profile 生成变体不一致;verify/speed-profile/speed 状态漂移;16 KB 页下 .so LOAD 段/ZIP 对齐不兼容。
  • 误区:Splash/KeepOnScreenCondition 只能管理感知,不应隐藏关键路径;盲目多线程/拆进程会增加锁、序列化、常驻内存和一致性成本。

5. 内存泄漏 / OOM / 低内存压力

  • 分域记账:Java heap、Native heap、Graphics、Code、Stack、mmap、FD、线程、WebView renderer、AI 运行时峰值不能混成一个"内存"。
  • Java 高频泄漏:静态持 Context/View;非静态内部类/匿名回调;未注销 Listener;协程/Flow 作用域未取消;单例缓存无界。
  • 资源高频泄漏:Bitmap 未按显示尺寸解码;图片复用池/inBitmap/Hardware Bitmap 边界不清;Camera/Codec/GL texture;Cursor/FD 未关。
  • 系统边界:PSS 按共享分摊,RSS 会重复计共享页;Private_Dirty 更适合定位写时复制增长;低内存下 lmkd、mmd/ZRAM、freezer、PSI/refault 会改变体验。
  • 证据:开发期 LeakCanary;线上 ApplicationExitInfo + ProfilingManager/OOM trigger + heap dump/heapprofd;Native 用 Scudo/GWP-ASan/MTE 分层,而不是只看一个总数。

6. 耗电 / 发热 / Thermal

  • 高频根因:WakeLock/Alarm/定位/蓝牙扫描/传感器未按业务生命周期关闭;后台任务重复唤醒;前台服务当免死金牌;Job/WorkManager 未看 pending/stop reason、bucket、配额。
  • 性能联动:长期高 CPU/GPU 负载触发 thermal throttling;应结合 ADPF PerformanceHint、thermal headroom、Game Mode/Game State 做降级。
  • 设备变量:亮度、刷新率、深色模式、网络制式、省电模式、电池健康、设备老化都会改变结果;记录请求值和生效值。
  • 证据:Battery Historian/dumpsys batterystats + Perfetto power rail/thermal + 线程 wakeup/锁;用 A/B 功耗实验验证收益,而不是只看 FPS。

7. 崩溃 / Native / 进程退出

  • Java Crash:未捕获异常、生命周期/配置变更错误、协程异常传播、后台启动违规;关注安全恢复与退出线程。
  • Native Crash:越界、use-after-free、泄漏、线程 attach/detach 错误;需要 Build ID/symbol 与 signal handler 交接边界。
  • 进程退出:OOM、低内存 kill、CPU 过量终止、ANR、force-stop、升级、WebView renderer、FD 耗尽;用 ApplicationExitInfo 与 tombstone/ANR/低内存字段互证。
  • 16 KB/ABI:包含 NDK 或三方 .so 的应用要检查 ELF LOAD 段对齐、APK 内未压缩 lib 的 ZIP 对齐、mmap/页掩码常量;Android 15 起支持 16 KB,Android 16 有兼容模式,Android 17 有测试 fatal 开关。

8. I/O、存储、SQLite、媒体

  • SharedPreferences:apply() 返回快不代表落盘完成;组件收尾路径仍可能阻塞主线程;多进程一致性不要靠 SP。
  • SQLite/Room:主线程查询、大事务、缺索引/坏查询计划、WAL checkpoint、连接池争用是常见根因。
  • 媒体/共享存储:MediaProvider/Photo Picker/FUSE/SAF/URI/FD 生命周期复杂;不要把 Provider 路径当普通文件。
  • OTA/首启:dexopt、odsign、快照合并、ZRAM/mmd、文件系统、16 KB page、I/O 竞争都可能让"升级后第一次慢";应与 App 代码问题分开。

9. Binder / IPC / 跨进程

  • 高频根因:主线程同步 Binder 长事务;小粒度 IPC 循环;oneway 滥发导致背压;大对象塞 Parcel 触发 TransactionTooLarge;服务线程池耗尽。
  • 正确边界:Binder 不只是"一次拷贝";端到端延迟包含排队、调度、SELinux/权限、对象解析、目标服务执行和下游依赖。
  • 进程冻结:cached freezer 会让线程轨迹空白;同步调用、oneway、异步缓冲区、解冻原因要分开看。
  • 证据:调用方 slice + Binder flow + 目标线程状态 + 下游事务 + buffer/对象图;不要把 PostFork/USAP 路径混为普通 fork。

10. 网络

  • 高频根因:DNS/TLS/TCP/QUIC 叠加在首屏关键路径;同步回调中做 HTTPDNS;弱网重试无预算;图片/Feed 一次拉全量;后台同步不区分计费网络/Data Saver。
  • 口径:客户端阶段耗时要和接入层对账;网络切换要同时约束解析和 socket;QUIC/HTTP3 字段显式区分;不能只看 dnsStart/dnsEnd。
  • 后台:JobScheduler/WorkManager 记录 pending reason、stop reason、standby bucket、配额;前台服务不自动豁免配额。

11. 最容易被忽略:归因与版本

  • 升级后 48--72 小时:dexopt、缓存重建、索引、云端画像、后台同步会扰动结论;应区分 OTA 首启、冷启动、稳定态。
  • 版本坐标:build fingerprint、API/targetSdk、compat change、Mainline/ART APEX、kernel uname -r、ABI、getconf PAGE_SIZE、厂商 ROM/调度/温控。
  • 指标坐标:P50/P90/P95/P99、分位数、样本量、场景入口、剔除规则;不要只看平均值或单次 trace。
  • A/B 原则:同设备、同构建、同启动类型、同 workload、同编译状态;收益要同时看耗时、内存、功耗、稳定性和长尾。

12. 通用排查 SOP

  1. 定义问题:选择正确类别和指标,明确起点/终点;卡顿看 deadline,启动看 TTID/TTFD,内存分域,功耗按场景。
  2. 固定状态:版本、targetSdk、编译模式、Profile、设备、温度、电量、网络、后台任务;记录构建指纹和 Mainline/ART 版本。
  3. 采集证据:线上 Vitals/APM/JankStats;实验室 Macrobenchmark;深度 Perfetto 同步抓 CPU/调度/Binder/I/O/内存/GC/渲染/功耗。
  4. 定位阻塞方:线程状态 + wakeup/futex/Binder/I/O/GC + 锁持有者 + thermal/freq;避免把最长 slice 直接当根因。
  5. 源码锚点:平台按 android-17.0.0_r1,内核按 android17-6.18-2026-06_r6;区分 AOSP 公共机制、Mainline 模块、OEM 实现。
  6. 修复验证:先减少关键路径工作,再改布局/编译/缓存/调度;用同状态 A/B 验证收益,并把指标加入 CI/灰度门禁。

13. 指标与警戒线参考

指标 常用参考 说明
慢帧 >16ms;高刷下 90Hz≈11ms、120Hz≈8.3ms 预算随刷新率变化,不能固定按 60fps
冻帧 >700ms 接近"卡死近一秒",Vitals 重点关注
ANR Input≈5s;前台广播≈10s/后台≈60s;Service≈20s;FGS 启动更严格 组件类型不同,计时窗口不同
启动 cold >5s、warm >2s 高优;中低端 cold 目标 1.5--2s 工程门禁常严于 Play 底线
崩溃/ANR 质量 Play user-perceived ANR 0.47%、crash 1.09% 等 适合做线上告警和发版暂停线,不替代 A/B
内存 分域看 PSS/Private_Dirty/Native/Graphics/FD 不要只用 RSS 或单一总数
功耗 stuck wakelock、过量唤醒、后台扫描/网络 按业务场景和设备分级设定阈值

14. 参考来源

  • Android Developers / Android Vitals:性能与电池质量指标、ANR、慢渲染、冻帧、启动、内存、功耗口径。
  • Android 官方 Android 17 发布信息:Pixel 首批推送、应用内存限制、高清游戏掉帧优化等方向。
  • 社区反馈:9to5Google Android 17 升级后读者投票、XDA/Reddit/厂商社区中的卡顿、耗电、升级后变慢个案;仅作体验线索。
  • 《Android 技术内幕:系统机制、性能优化与工具实战》(你提供的文档):AOSP android-17.0.0_r1 与 ACK android17-6.18-2026-06_r6 的源码锚点、版本边界和工具方法。
相关推荐
高旭的旭2 小时前
图解 Android 系统架构:从 App、Framework、HAL 到 Linux 驱动
android·linux·系统架构
hunterandroid2 小时前
Navigation Component 多模块导航与深度链接实战
android
快乐非自愿2 小时前
低代码落地费控系统:从报销流程到业财闭环的实操方案
android·低代码·rxjava·ai低代码
摇滚侠3 小时前
《Java并发编程之美》第 2 章 并发编程的其他基础知识 阅读笔记 3
android·java·笔记
YB13753 小时前
Jetpack Compose 动画updateTransition
android
用户2018792831673 小时前
给主厨装一台打卡机:一文搞懂 Android APM 性能监控原理
android
我不会插花弄玉4 小时前
8. 复合查询【由浅入深-MySQL】
android·数据库·mysql
熊文豪5 小时前
机器人开发者生态分析:行业分工变化与启元的定位
android·机器人·启元机器人
郑州光合科技余经理5 小时前
同城商城源码:商品库和订单库怎么随包交付
android·java·开发语言·后端·uni-app·php·ai编程