18、性能优化:启动时间优化(Boot Time),内存管理,ANR 与卡顿分析
性能优化,说白了就是让车机系统跑得更快、更稳、更省资源。在 Android Automotive OS 里,这三点尤其关键——启动慢了,用户骂;内存爆了,系统崩;卡顿多了,体验差。今天我就把这三大块掰开揉碎了讲清楚。
18.1 启动时间优化(Boot Time)
车机启动,用户最敏感。从按下点火开关到中控屏亮起,这个时间窗口就是第一印象。我个人习惯把启动优化分成三个阶段:Bootloader → Kernel → Android Framework。
18.1.1 Bootloader 阶段
这个阶段其实能做的有限。Bootloader 主要负责加载内核,时间通常控制在几百毫秒内。我见过有些项目在 Bootloader 里加了大量日志打印,结果白白浪费了 200ms。嗯,这里要注意:关掉不必要的调试输出。
18.1.2 Kernel 阶段
内核启动时间主要花在驱动加载上。你可以通过 initcall_debug 内核参数来查看每个驱动的加载耗时。
# 在 kernel cmdline 中添加
initcall_debug loglevel=8
# 启动后查看
dmesg | grep "initcall" | sort -k5 -n -r | head -20
我曾经在一个项目里发现,某个触摸屏驱动加载花了 1.2 秒。查了半天,原来是驱动里做了三次 I2C 通信重试。改成一次后,直接降到 300ms。
18.1.3 Android Framework 阶段
这是优化空间最大的阶段。核心思路就一句话:能并行就别串行,能懒加载就别提前加载。
| 优化手段 | 说明 | 预期收益 |
|---|---|---|
| 精简 SystemServer 服务 | 只启动核心服务,非核心服务按需启动 | 减少 500ms-1s |
使用 zygote 预加载 |
提前加载常用类和资源 | 减少 200ms-400ms |
优化 init.rc 脚本 |
合并同类服务,减少进程创建开销 | 减少 300ms-600ms |
使用 bootchart 分析 |
可视化启动瓶颈 | 定位问题 |
surfaceflinger 的启动延迟了,结果导致开机动画花屏。嗯,这个坑我踩过。
18.2 内存管理
车机内存不像手机那么充裕。很多车型还在用 2GB 甚至 1GB 的 RAM。内存管理做不好,系统分分钟被 OOM Killer 干掉。
18.2.1 内存泄漏检测
我个人最常用的工具是 dumpsys meminfo 和 leakcanary。但车机环境特殊,LeakCanary 有时会误报。我建议用 adb shell dumpsys meminfo -s 先看个大概。
# 查看整体内存分布
adb shell dumpsys meminfo -s
# 查看某个进程的详细内存
adb shell dumpsys meminfo com.android.car
我曾经在车载蓝牙模块里发现一个内存泄漏:每次蓝牙断开重连,就会多分配一个 4KB 的缓冲区,但释放代码写错了条件。结果跑了一周后,蓝牙服务占用了 200MB 内存。嗯,这种问题用 dumpsys 配合 top 就能发现。
18.2.2 内存压缩与回收
Android 内核支持 zRAM 和 kswapd。车机上我建议开启 zRAM,但压缩比例别太高。我一般设 50%,压缩比太高反而增加 CPU 开销。
# 查看 zRAM 状态
adb shell cat /sys/block/zram0/mm_stat
# 设置 zRAM 大小(以 512MB 为例)
echo 536870912 > /sys/block/zram0/disksize
kswapd,而不是等到内存紧张了再回收。
18.2.3 应用内存限制
车机上每个应用都应该有内存上限。通过 ActivityManager 的 setMemoryClass() 可以控制。我建议把车载应用的 heap 上限设为 128MB,地图类应用可以放宽到 256MB。
// AndroidManifest.xml 中设置
<application
android:largeHeap="true"
android:hardwareAccelerated="true">
</application>
18.3 ANR 与卡顿分析
ANR(Application Not Responding)是用户最反感的体验之一。车机上 ANR 的后果更严重——可能影响导航、倒车影像等安全功能。
18.3.1 ANR 的常见原因
- 主线程耗时操作:比如网络请求、数据库查询、文件读写
- 锁竞争:多个线程争抢同一个锁,导致主线程被阻塞
- Binder 调用超时:跨进程通信卡住
- CPU 过载:系统负载太高,主线程拿不到时间片
我记得有一次排查 ANR,发现是某个第三方地图 SDK 在后台线程里做了大量计算,把 CPU 占满了。主线程的触摸事件根本得不到响应。解决方案很简单:给后台线程设置优先级。
Thread backgroundThread = new Thread(() -> {
// 降低优先级
android.os.Process.setThreadPriority(
android.os.Process.THREAD_PRIORITY_BACKGROUND);
// 执行耗时操作
});
backgroundThread.start();
18.3.2 卡顿分析工具
卡顿分析我常用三个工具:Systrace、SimplePerf、Choreographer 回调。
| 工具 | 适用场景 | 使用方法 |
|---|---|---|
| Systrace | 整体性能分析 | python systrace.py -t 10 |
| SimplePerf | CPU 热点定位 | simpleperf record -p [pid] |
| Choreographer | 帧率监控 | 注册 FrameCallback |
18.3.3 实战:解决一个卡顿问题
我曾经在车载 Launcher 上遇到一个卡顿:滑动应用列表时,帧率从 60fps 掉到 20fps。用 Systrace 一看,发现每次滑动都触发了 onLayout() 重排。原因是列表项里用了 RelativeLayout 嵌套,每次测量都要遍历所有子 View。
解决方案:
- 把
RelativeLayout改成ConstraintLayout - 对列表项启用
setHasFixedSize(true) - 使用
RecyclerView的Prefetch特性
// 启用预取
recyclerView.setLayoutManager(new LinearLayoutManager(this) {
@Override
protected int getExtraLayoutSpace(RecyclerView.State state) {
return 300; // 预取 300px 的内容
}
});
改完之后,帧率稳定在 55fps 以上。嗯,这种问题其实很常见——说白了就是布局太复杂了。
18.4 本章知识体系
下面这张图总结了本章的核心内容。你可以把它当作一个检查清单,做优化时对照着看。
性能优化没有银弹。每个项目的情况都不一样,关键是要学会用工具、看数据、做实验。我个人习惯是:先定目标(比如启动时间 < 5s),然后测量当前值,再针对瓶颈做优化。嗯,别想着一步到位,迭代优化才是正道。
公众号:蓝海资料掘金营,微信deep3321