建立稳定的基准测试环境
做性能优化,第一步不是调代码,而是先搞清楚“现在到底有多慢”。
但很多人上来就踩坑——同样的SDK,今天测CPU 5%,明天测变成15%。你说是SDK抽风?不,很可能是你的测试环境在抽风。
基准测试最核心的一句话:消除变量,才能看清真相。
环境隔离:别让隔壁进程干扰你
我在项目中最常见的问题——测试机后台挂着微信、推着消息、跑着定时任务。你想想看,这种环境测出来的数据能信吗?
我建议至少做到以下几点:
- 专用测试机:不要用日常开发机,别装无关APP
- 飞行模式:关闭Wi-Fi、蓝牙、移动数据,避免网络波动和后台唤醒
- 清理后台进程:执行
adb shell am force-stop干掉所有非目标应用 - 禁止自动更新:关掉系统更新、应用商店自启
注意了:部分厂商手机有“省电模式”、“性能模式”,这些会动态调频CPU。测试时必须锁定同一模式。我曾经被“智能省电”坑过两整天,数据忽高忽低完全找不到原因。
硬件固定:CPU频率、屏幕亮度、温度
搞基准测试,说白了就是让手机处于“焊死”的状态。下面这张表格总结了我平时锁定的硬件参数:
| 硬件参数 | 推荐设置 | 为什么重要 |
|---|---|---|
| CPU大核频率 | 锁定到中间档位(如1.8GHz) | 避免降频/变频导致的测量误差 |
| GPU频率 | 固定为最低或中间档 | 减少渲染波动对CPU时间片的抢占 |
| 屏幕亮度 | 固定50%并关闭自动亮度 | 亮度变化影响功耗,功耗影响温度,温度影响降频 |
| 手机温度 | 控制在35°C以下(先静置10分钟) | 过热会触发温控策略,直接限制性能 |
| USB连接 | 使用有线连接,不接扩展坞 | 无线adb或外设可能引入额外中断 |
一个小技巧:用
adb shell 配合 /sys/devices/system/cpu/cpu0/cpufreq/scaling_governor 将调度器设为“performance”,再用 scaling_setspeed 手动锁频。我习惯写个脚本,跑测试前一键执行。
数据采样:跑几次才够?
一次跑出来的数据叫“运气”,十次跑出来的才叫“结论”。
我个人习惯遵循3-5-3原则:
- 预热跑3次(让JIT编译、缓存预热完成)
- 正式采样跑5次(记录每次的CPU、内存峰值与均值)
- 取中位数加标准差进行汇报(剔除异常值)
为什么会这样?第一次跑时很多代码还没被JIT编译,内存分配也慢。五六次之后基本稳定下来,那才是真实表现。
数据记录:永远留下原始日志
别只记结论。我在项目中吃过亏——改了一版SDK,觉得内存降了20%,但回头想对比原始数据,发现之前只记了个“大概”。
建议至少记录以下字段:
- 时间戳、测试机型号、系统版本
- CPU整体占用、SDK所在线程占用
- Java Heap / Native Heap / 虚拟内存
- GC次数、GC暂停时间
- 帧率、卡顿次数(涉及UI线程时)
知识结构总览
我把整个稳定基准测试的核心逻辑画成了下面这张图,方便你一眼看懂流程:
避坑指南:我踩过的三个坑
经验都是拿加班换来的。下面这几个坑,你最好一次都不要踩:
- “原来测试机没Root”:没Root就没办法锁频,数据每次都不一样。我后来买了三台一样的测试机,全Root,一台专门跑CPU基准。
- “Wi-Fi没关”:接收消息推送会触发网络I/O,进而影响CPU占用。说白了就是多了不可控的中断。
- “跑完直接看总和”:SDK接入后的CPU峰谷差异可能很大,只看均值会掩盖瞬时尖刺。我建议把单次采样时间控制在100ms以内,才能真实反映抖动。
写在最后
基准测试不是“跑个分”就完了。它的真正价值,是让你在优化前后有同一把尺子去量。
把环境焊死,把流程标准化,把数据留全——做到这三点,你手里的CPU和内存数据才有说服力。下一回再有人质疑你的优化方案,直接甩出带标准差的历史曲线,比任何PPT都管用。