第2章 移动端基准测试目标:冷启动、热启动、页面加载、内存基线

移动端基准测试的目标是建立可重复、可对比的性能基线,用于捕捉性能退化、验证优化效果。本章定义四个核心测试场景:冷启动、热启动、页面加载和内存基线。每个场景都有明确的触发条件、测量指标和采集工具。理解这些目标的差异,是后续压测实施和CI集成的基石。

2.1 冷启动基准测试

原理:冷启动指进程被系统完全杀死后,用户首次点击应用图标到首屏内容完全绘制完成的过程。此阶段包括进程创建、主线程初始化、类加载、Application 和 Activity 生命周期、布局 inflate 等环节,对用户体验影响最大。

实现流程

  1. 确保应用进程未运行:adb shell am force-stop <package>
  2. 清除系统缓存(可选):adb shell pm clear <package>(仅可用于首次启动测试,后续采集需谨慎,避免破坏持久化状态)
  3. 启动应用并记录启动完成事件:adb shell am start -W <package>/.<Activity>
  4. 解析输出的 ThisTime、TotalTime、WaitTime,取多次测量中位数或P95。

关键指标:TotalTime(从进程创建到首帧渲染完毕的时间,单位毫秒),行业参考:冷启动应 < 2s(中端设备),< 1.5s(旗舰设备)。

常用命令与自动化脚本示例

# 冷启动单次测量
adb shell am force-stop com.example.app
adb shell am start -W com.example.app/.MainActivity | grep TotalTime

# 批量采集 10 次(需要 sleep 间隔,避免系统重排)
for i in $(seq 1 10); do
  adb shell am force-stop com.example.app
  sleep 2
  adb shell am start -W com.example.app/.MainActivity | grep TotalTime >> cold_start.txt
done

2.2 热启动基准测试

原理:热启动指应用进程已在后台存活(未被系统杀死),用户重新从桌面切换回应用时的启动体验。应用对象保留在内存中,主要开销为 Activity 重建(onCreate/onStart/onResume),无需重新初始化整个进程和 Application。热启动时间通常只有冷启动的 1/3~1/2。

实现流程

  1. 先让应用完全冷启动一次,进入待测试页面。
  2. 模拟 Home 键切后台:adb shell input keyevent KEYCODE_HOME
  3. 等待 1~2s 后,重新启动目标 Activity:adb shell am start -W <package>/.<Activity>
  4. 记录 TotalTime,注意与冷启动差异:热启动的 TotalTime 应远小于冷启动,否则可能发生了进程被系统回收(实质仍是冷启动)。

验证进程是否存活:用 adb shell ps | grep <package> 检查,若不存在则视为冷启动,需剔除。

典型热启动指标:热启动 < 700ms(中端设备),< 400ms(旗舰设备)。

2.3 页面加载基准测试

原理:页面加载测试聚焦于应用内部次级页面(非首屏)的打开性能,例如电商App的商品详情页、Feed列表页的滑动加载。测试通过自定义 Activity 曝光回调或自动化工具(如 Espresso、UI Automator)触发页面跳转,并收集 firstPaint、firstContentfulPaint、onNextDraw 等前端感知指标。

实现流程

  • 定义页面加载结束标志:通常使用 ViewTreeObserver.OnDrawListener 或 ReportFullyDrawn() API。
  • 在测试环境中,使用 adb shell am start -W 配合特定 Intent 跳转到子页面。
  • 对于列表页的滚动加载(如 RecyclerView),需记录 首帧完成时间 和 列表第一次充满屏幕时间。

采集命令示例(子页面跳转)

# 假设商品详情页 Activity 为 .ProductDetailActivity,需传入商品 ID
adb shell am start -W com.example.app/.ProductDetailActivity \
  --es "product_id" "12345" | grep TotalTime

注意事项:页面加载测试强烈依赖网络状态(若页面有网络请求),应在控制网络延迟(如使用弱网模拟工具)或缓存数据的条件下测试。建议区分首次加载(无缓存)和二次加载(缓存命中)。

2.4 内存基线测试

原理:内存基线测试旨在量化应用在不同场景下的PSS(Proportional Set Size)、Java Heap、Native Heap 和 Graphics 等内存使用分布。目标有两个:一是确认应用在承受压力前的内存基线值;二是发现内存泄漏或异常增长。

关键工具与命令

  • adb shell dumpsys meminfo <package> —— 获取当前进程的内存快照。
  • /proc/meminfo 结合 /proc/<pid>/status 可以细粒度分析。
  • 自动化推荐使用 adb shell top 或 dumpsys gfxinfo 配合脚本循环采集。

典型场景与基线脚本示例

# 在页面加载完成后采集内存快照
adb shell dumpsys meminfo com.example.app | grep "TOTAL" >> mem_base.txt

# 循环 30 秒,每秒采集一次(用于检测泄漏)
for i in $(seq 1 30); do
  adb shell dumpsys meminfo com.example.app | grep "TOTAL PSS" | awk '{print $3}' >> pss_series.txt
  sleep 1
done

基线判定:取多次测量中位数作为基线值。若某次采集的 PSS 高于基线 + 20% 且持续不回落,应视为内存异常,需触发告警。

采集建议:内存基线测试需在多种场景下进行:刚启动、浏览主页面、浏览子页面、后台驻留 10 分钟、从后台切回。每种场景采集 5~10 次,计算中位数作为该场景基线。
注意:不同 Android 版本及厂商定制系统对内存统计存在差异。建议统一使用 adb shell dumpsys meminfo -s(简略模式)以保证跨设备可比性。若使用 procrank 等工具,需确保设备已 root。

2.5 四个基准测试目标对比

测试目标 触发条件 核心指标 典型工具/命令 建议采集次数
冷启动 进程完全不存在 TotalTime (ms) am start -W + force-stop ≥ 10 次
热启动 进程存活,重新前台 TotalTime (ms) am start -W 在后台后执行 ≥ 8 次
页面加载 内部页面首次跳转 TotalTime / firstPaint (ms) am start -W + Intent / ReportFullyDrawn() ≥ 5 次(区分缓存状态)
内存基线 稳定场景下的内存快照 PSS (kB)、Java Heap (kB) dumpsys meminfo / procrank ≥ 10 次(每场景)

2.6 基准测试总体流程(内联SVG)

移动端基准测试总体流程 准备设备与测试环境 选择测试场景 冷启动 热启动 页面加载 内存 & 性能指标采集 结果分析 & 基线入库 CI 集成 / 回归告警 注:每次测试前需清理后台进程

图中展示了从准备设备到最终 CI 告警的完整链路。实际执行时,冷启动、热启动和页面加载测试可以并行或按序执行,但内存基线测试必须至少在每种场景稳定后采集,以保证基线代表真实运行状态。