You need to enable JavaScript to run this app. 为何使用performance.now()测试的JS函数执行时间不随数组长度线性增长?
优惠活动
大模型
产品
解决方案
定价
更多

为何使用performance.now()测试的JS函数执行时间不随数组长度线性增长?

异常耗时的核心原因

1. V8 引擎 JIT 编译的预热效应

V8 引擎启动阶段不会直接把 JS 代码编译成高性能机器码,先用解释器执行保证启动速度。只有当同一个函数被反复调用、达到引擎预设的优化阈值后,才会将其编译为优化后的机器码。

  • 测试前两次调用(对应 10 万、20 万长度数组)时,getMaxSequence 还处于未优化的解释执行状态,因此耗时偏高
  • 到第三次调用时,引擎刚好完成对该函数的 JIT 优化,后续执行速度直接大幅下降,直接打破了线性增长的预期

2. 数组与循环的优化滞后

V8 对 JS 数组有分级内存优化策略,存储连续小整数的 PACKED_SMI_ELEMENTS 类型数组访问速度最快。

  • 前两次遍历数组时,引擎还未识别出数组的连续整数特征,默认使用通用、低效率的访问模式
  • 连续遍历几次后,引擎确认了数组的元素类型和顺序访问规律,会切换到紧凑存储 + CPU 缓存预取的优化策略;同时识别出循环内的条件判断永远走“递增”分支,提前做分支预测,进一步减少判断开销,拉低了后续执行耗时

3. 测试方法缺陷放大了结果波动

  • 未执行预热用例就直接开始正式测试,把冷启动阶段的未优化耗时直接计入结果
  • 每个数组长度的用例仅执行 1 次,没有重复测试取平均值。JS 单线程执行会被系统进程调度、GC 停顿、CPU 睿频波动等因素干扰,单次测试的误差本身就很大
  • 提前将所有测试数组存在 randoms 常量中,长度更大的数组在遍历前已经被预读到 CPU 缓存中,进一步降低了大数组的实际测试耗时
正确测试的调整方案
  • 先运行 3-5 次任意长度的测试用例做预热,等引擎完成 JIT 优化后再开始正式统计
  • 每个长度的用例重复执行 3-10 次,去掉最高、最低误差值后取平均耗时
  • Node 环境下可加 --expose-gc 参数启动,每次测试完成后主动调用 global.gc() 避免垃圾回收干扰
  • 按需生成对应长度的测试数组,不要提前缓存所有测试用例,避免缓存预取影响结果准确性

内容的提问来源于stack exchange,提问作者Jarek Mazur

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.11.08 09:45:04