You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

Java方法中较早执行的语句理应运行速度更慢吗?

Stream收集ArrayList性能测试顺序偏差问题解析

观测到的性能结果与执行顺序强相关的现象,和两种ArrayList初始化逻辑的真实性能差异无关,是不规范微基准测试下JVM与CPU运行机制共同导致的典型测试误差。


测试场景回顾

测试目标为对比Stream元素收集到默认容量ArrayList、预定义容量ArrayList的性能差异,核心测试代码如下:

int capacity = 8000; 
var master = new ArrayList<Integer>(capacity); 
for (int i = 0; i < capacity; i++) {
    master.add(rnd.nextInt()); 
}
print("Adding elements to list with default capacity..."); 
var sw = Stopwatch.startNew();
List<Integer> defaultList = 
         master
        .stream()
        .collect(Collectors.toList()); 
sw.stop();
String elapsedDefault = sw.toString(); 
print("Adding elements to list with predefined capacity..."); 
sw.restart();
List<Integer> predefined = 
         master
        .stream()
        .collect(Collectors.toCollection(() 
                -> new ArrayList<>(master.size())));
sw.stop();
String elapsedPredefined = sw.toString(); 
System.out.println("Time taken with default size: " + elapsedDefault); 
System.out.println("Time taken with predefined size: " + elapsedPredefined);

当默认容量收集逻辑先执行时,测试输出为:

Adding elements to list with default capacity...
Adding elements to list with predefined capacity...
Time taken with default size: 12.63ms
Time taken with predefined size: 3.66ms

调换执行顺序,让预定义容量收集逻辑先执行时,输出变为:

Adding elements to list with predefined capacity...
Adding elements to list with default capacity...
Time taken with predefined size: 13.17ms
Time taken with default size: 3.23ms


偏差产生的核心原因

  • JIT编译预热开销:JVM启动初期采用解释模式执行字节码,只有代码被反复执行触发编译阈值后,JIT即时编译器才会将其优化编译为本地机器码,执行效率会有数倍提升。测试中先执行的逻辑永远处于解释执行或未完成全量优化的状态,后执行的逻辑可以直接复用JIT对Stream调用链、ArrayList操作的编译优化结果,因此无论测试的是哪种初始化逻辑,永远是先执行的用例耗时更高,和是否预分配容量没有关联。
  • CPU硬件层面的预热开销:第一次执行相关代码时,对应的指令、操作数据还未加载到CPU多级缓存中,分支预测器也没有积累对应的执行历史,访存延迟、分支预测失败的回滚开销会远高于后续重复执行的场景,这部分额外开销会被全部计入先执行的测试用例耗时中。
  • 运行时噪声干扰:第一次执行集合收集时产生的临时对象可能触发新生代GC,JVM后台编译线程、GC线程的调度带来的额外停顿,也会叠加在先执行的测试结果上,对于毫秒级的小数据量测试来说,这类干扰足以完全盖过真实的性能差异。

实际性能规律

测试备注中提到的规律符合真实场景:

  • 小数据量(如本次测试使用的8000元素级别)下,ArrayList动态扩容触发的数组拷贝开销本身极小,很容易被上述运行时噪声掩盖,无法测出稳定的性能差异。
  • 只有当元素规模达到数亿级别时,预分配容量省去的多次数组拷贝、内存申请开销才会累积出可稳定观测的性能优势。

如果要得到准确的微基准测试结果,需要先做多轮预热、多次重复测试取平均值,过滤掉运行时噪声的影响,不能直接用单次执行的耗时下结论。


内容的提问来源于stack exchange,提问作者Fiery Phoenix

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.08.26 17:18:41