ART 与内存
Android 运行在 ART(Android Runtime),分代 GC 回收对象。频繁分配大对象/短命对象会触发 GC 卡顿,应复用与对象池。
高分配率(allocations/sec)引起频繁 GC,表现为周期性掉帧。用 Profiler 的 Memory 面板查看分配热点。
内存泄漏
长生命周期对象(单例、静态)持有 Activity/Fragment/Context 强引用,导致本应回收的界面无法释放。
// 反例:单例持 Activity 引用 → 泄漏
object Analytics { lateinit var ctx: Context } // 用 ApplicationContext
// 正例
object Analytics { lateinit var ctx: ApplicationContext }LeakCanary
LeakCanary 在开发包自动检测 Activity/Fragment 泄漏,堆转储并展示引用链,是定位泄漏的利器。
用 debugImplementation 引入,release 自动移除,不影响生产体积。
启动优化
冷启动分系统进程创建→Application→首屏绘制。减少 Application.onCreate 与主线程同步重活是核心。
// 反例:Application 里同步初始化重活
override fun onCreate() { super.onCreate(); initHugeSDK() /* 阻塞 */ }
// 正例:延迟到首屏之后
lifecycleScope.launch(Dispatchers.Default) { initHugeSDK() }用 Baseline Profile 预编译关键路径,可显著缩短冷启动,是官方推荐手段。
渲染与卡顿
每帧 16ms(60fps)预算,超期即掉帧(jank)。过度绘制(多层重叠背景)、主线程重活、频繁布局是主因。
网络、数据库、图片解码必须离主线程;用协程 Dispatchers.IO/Default 与 Coil/Glide 后台加载。
列表性能
RecyclerView 用 DiffUtil/ListAdapter 只更新变化项;避免在 onBind 里做分配或 IO;图片用异步库并复用。
电量与后台
Doze 模式与后台限制会挂起后台任务。合并网络、用 WorkManager 调度可延迟工作、定位用单次获取而非常驻。
- WorkManager。持久化、可约束(充电/联网)的后台任务。
- 合并请求。减少射频唤醒次数。
- 定位按需。单次
getCurrentLocation而非持续监听。
常见陷阱
基本是泄漏:长生命周期对象持有界面。用 LeakCanary 抓引用链,把 Context 换成 ApplicationContext、解绑监听。
用 CPU Profiler 抓主线程热点,通常 onBind 里有同步解码/分配。移到后台、用 DiffUtil 减少刷新。