18、性能优化:启动时间优化(Boot Time),内存管理,ANR 与卡顿分析

性能优化,说白了就是让车机系统跑得更快、更稳、更省资源。在 Android Automotive OS 里,这三点尤其关键——启动慢了,用户骂;内存爆了,系统崩;卡顿多了,体验差。今天我就把这三大块掰开揉碎了讲清楚。

18.1 启动时间优化(Boot Time)

车机启动,用户最敏感。从按下点火开关到中控屏亮起,这个时间窗口就是第一印象。我个人习惯把启动优化分成三个阶段:Bootloader → Kernel → Android Framework

18.1.1 Bootloader 阶段

这个阶段其实能做的有限。Bootloader 主要负责加载内核,时间通常控制在几百毫秒内。我见过有些项目在 Bootloader 里加了大量日志打印,结果白白浪费了 200ms。嗯,这里要注意:关掉不必要的调试输出

我的经验: 在 Bootloader 里只保留最核心的硬件初始化,比如 DDR、存储控制器。其他外设初始化可以推迟到内核阶段。

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 meminfoleakcanary。但车机环境特殊,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 内核支持 zRAMkswapd。车机上我建议开启 zRAM,但压缩比例别太高。我一般设 50%,压缩比太高反而增加 CPU 开销。

# 查看 zRAM 状态
adb shell cat /sys/block/zram0/mm_stat

# 设置 zRAM 大小(以 512MB 为例)
echo 536870912 > /sys/block/zram0/disksize
核心原则: 车机内存管理要「主动回收,避免 OOM」。我习惯在系统空闲时主动触发 kswapd,而不是等到内存紧张了再回收。

18.2.3 应用内存限制

车机上每个应用都应该有内存上限。通过 ActivityManagersetMemoryClass() 可以控制。我建议把车载应用的 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 卡顿分析工具

卡顿分析我常用三个工具:SystraceSimplePerfChoreographer 回调。

工具 适用场景 使用方法
Systrace 整体性能分析 python systrace.py -t 10
SimplePerf CPU 热点定位 simpleperf record -p [pid]
Choreographer 帧率监控 注册 FrameCallback
我的习惯: 先用 Systrace 看整体,找到可疑的帧后,再用 SimplePerf 定位具体函数。不要一上来就钻细节。

18.3.3 实战:解决一个卡顿问题

我曾经在车载 Launcher 上遇到一个卡顿:滑动应用列表时,帧率从 60fps 掉到 20fps。用 Systrace 一看,发现每次滑动都触发了 onLayout() 重排。原因是列表项里用了 RelativeLayout 嵌套,每次测量都要遍历所有子 View。

解决方案:

  • RelativeLayout 改成 ConstraintLayout
  • 对列表项启用 setHasFixedSize(true)
  • 使用 RecyclerViewPrefetch 特性
// 启用预取
recyclerView.setLayoutManager(new LinearLayoutManager(this) {
    @Override
    protected int getExtraLayoutSpace(RecyclerView.State state) {
        return 300; // 预取 300px 的内容
    }
});

改完之后,帧率稳定在 55fps 以上。嗯,这种问题其实很常见——说白了就是布局太复杂了。

18.4 本章知识体系

下面这张图总结了本章的核心内容。你可以把它当作一个检查清单,做优化时对照着看。

Android Automotive OS 性能优化体系 启动时间优化 内存管理 ANR 与卡顿 Bootloader Kernel Framework 泄漏检测 zRAM 应用限制 主线程阻塞 锁竞争 CPU过载 核心原则:并行加载 · 主动回收 · 避免主线程阻塞 推荐工具:bootchart · dumpsys · Systrace · SimplePerf · LeakCanary 图:Android Automotive OS 性能优化三大模块与关键手段

性能优化没有银弹。每个项目的情况都不一样,关键是要学会用工具、看数据、做实验。我个人习惯是:先定目标(比如启动时间 < 5s),然后测量当前值,再针对瓶颈做优化。嗯,别想着一步到位,迭代优化才是正道。

最后说一句: 车机性能优化,本质上是在「快、稳、省」三者之间找平衡。别为了快牺牲稳定性,也别为了省内存牺牲用户体验。这个度,需要你在实际项目中慢慢摸索。

公众号:蓝海资料掘金营,微信deep3321