相同函数不同运行时?新增代码为何影响Java排序算法计时结果
Java排序计时结果异常的原因与解决方案
你在测试百万级数据的排序算法时遇到了一个奇怪的现象:当只测试Collections.sort和自定义num.sort时,前者耗时6-7秒,后者2-3秒;但新增第三个排序函数的测试代码后,前者耗时降到3.8秒左右,后者反而升到5.9秒。换用Instant.now()也有同样问题,说明不是计时API的问题。
核心原因:JVM运行时优化与系统资源的动态变化
1. JIT即时编译的触发时机差异
JVM的即时编译器(JIT)不会一开始就把所有代码编译成最优机器码,而是统计代码调用次数,当方法成为热点代码后才会做优化编译:
- 只测两个函数时,程序整体运行时间短,
Collections.sort可能还没触发JIT优化就执行完了,而自定义排序方法先达到热点阈值被优化,所以耗时更短。 - 新增第三个测试后,程序总运行时间变长,JVM有足够时间在
Collections.sort执行前完成部分优化;同时自定义排序的优化可能因为编译资源被第三个函数抢占,导致优化延后,耗时上升。
2. CPU缓存与内存局部性的影响
排序性能极大依赖CPU缓存命中率:
- 第一次测试时,两个待排序列表的内存布局更紧凑,CPU缓存能更好命中数据,自定义排序的缓存利用率较高,所以跑的快。
- 新增第三个列表后,内存占用显著增加,CPU缓存被更多数据填充,
nonSortedList2的排序过程中缓存命中率下降,耗时自然上升。而Collections.sort是JDK团队深度优化的实现,对缓存利用效率更高,在内存压力下反而体现出优势。
3. GC与线程调度的干扰
新增代码后,程序创建的对象数量增加,JVM可能在测试过程中触发Minor GC,GC会抢占CPU资源,导致某个排序函数的计时被拉长。另外,操作系统的线程调度也会因为程序整体运行时间变长,给不同排序函数分配的CPU时间片出现波动,进一步影响计时结果。
解决方案:让计时结果更可靠的实践
- 预热代码:正式计时前,把所有要测试的排序函数循环执行多次(比如10次),触发JIT优化,确保正式测试时所有方法都处于优化状态。
- 多次取平均:单次计时误差极大,建议每个排序函数重复测试10-20次,去掉最大值和最小值后取平均值,减少偶然因素影响。
- 隔离测试:把每个排序函数的测试逻辑放在单独的Java程序中运行,避免不同测试之间的JVM状态、内存占用互相干扰。
- 固定测试数据:每次测试使用完全相同的待排序列表,比如把shuffle后的列表序列化保存,每次测试都加载同一个列表,避免shuffle的随机性导致数据分布差异影响结果。
测试代码
Function1 num1 = new Function1(); //Function2 num2 = new Function2(); ArrayList<Integer> nonSortedList = new ArrayList<>(); for (int i=1; i<10000000; i++) nonSortedList.add(i); Collections.shuffle(nonSortedList); ArrayList<Integer> nonSortedList2 = new ArrayList<>(nonSortedList); //ArrayList<Integer> nonSortedList3 = new ArrayList<>(nonSortedList2); System.out.println(); System.out.println(); long start = System.nanoTime(); Collections.sort(nonSortedList); System.out.println("function1= "+((System.nanoTime()-start)/1000000000.0)); start = System.nanoTime(); num.sort(nonSortedList2); System.out.println("function2= "+((System.nanoTime()-start)/1000000000.0)); /* start = System.nanoTime(); num2.sort(nonSortedList3); System.out.println("function3= "+((System.nanoTime()-start)/1000000000.0)); */
测试输出
无注释代码时输出:
function1= 6-7 seconds
function2= 2-3 seconds
包含注释代码时输出:
function1= 3.8144072
function2= 5.8931552
function3= 4.2656519
内容的提问来源于stack exchange,提问作者HelpAnElf
相关产品推荐
相关产品推荐

