下面的代码调用了两个简单的函数,每个函数都是10亿次.
public class PerfTest {
private static long l = 0;
public static void main(String[] args) {
List list = Arrays.asList("a", "b");
long time1 = System.currentTimeMillis();
for (long i = 0; i < 1E10; i++) {
func1("a", "b");
}
long time2 = System.currentTimeMillis();
for (long i = 0; i < 1E10; i++) {
func2(list);
}
System.out.println((time2 - time1) + "/" + (System.currentTimeMillis() - time2));
}
private static void func1(String s1, String s2) { l++; }
private static void func2(List sl) { l++; }
}
我的假设是,这两个电话的表现将接近于相同.如果有什么我会猜到通过两个参数会比通过一个稍慢.由于所有的参数都是对象引用,所以我并不期望有一个是一个列表来做任何改动.
我经历了很多次测试,典型的结果是“12781/30536”.换句话说,使用两个字符串的呼叫需要13秒,使用列表的呼叫需要30秒.
这个性能差异的解释是什么?还是这个不公平的考验?我已经尝试切换两个呼叫(如果是由于启动效果),但结果是一样的.
更新
这不是一个公平的考验,原因很多.但是它确实证明了Java编译器的真实行为.请注意以下两个补充说明:
>将表达式s1.getClass()和sl.getClass()添加到函数中,使两个函数调用相同
>使用-XX运行测试:-TieredCompilation还使得两个函数调用执行相同
这个行为的解释在下面接受的答案. @ apangin的答案的最简单的总结是,func2没有由热点编译器内联,因为它的参数(即List)的类没有被解析.强制解析类(例如使用getClass)会导致内联,这显着提高了其性能.正如答案中指出的那样,未解决的类不太可能发生在实际代码中,这使得该代码成为不切实际的边缘情况.