Java的varargs性能

编码我来检查Java的vararg性能。

我写下面的测试代码:

public class T { public static void main(String[] args) { int n = 100000000; String s1 = new String(""); String s2 = new String(""); String s3 = new String(""); String s4 = new String(""); String s5 = new String(""); long t = System.currentTimeMillis(); for (int i = 0; i < n; i++) { foo(); } System.err.println(System.currentTimeMillis() - t); t = System.currentTimeMillis(); for (int i = 0; i < n; i++) { baz(s1, s2, s3, s4, s5); } System.err.println(System.currentTimeMillis() - t); t = System.currentTimeMillis(); for (int i = 0; i < n; i++) { bar(s1, s2, s3, s4, s5); } System.err.println(System.currentTimeMillis() - t); } static void foo() { } static void bar(String a1, String a2, String a3, String a4, String a5) { } static void baz(String... a) { } } 

在我的机器上,平均输出是:

 78 4696 78 

似乎将变量传递给方法是免费的?! 好!

但是使用varags要慢60倍! 为什么?

解释可能是程序必须在堆上创建数组,并且GC花费的时间。 但是对于较少的循环,我仍然得到输出:

 0 62 0 

什么是花费这个额外的时间,无论如何编译器都有所有信息来解决这个问题到一个修复变量调用…

我不打算优化它,但我发现这很奇怪……

更新

我添加了一个新的测试

 t = System.currentTimeMillis(); for (int i = 0; i < n; i++) { baz(s1); } System.err.println(System.currentTimeMillis() - t); 

而这一个论点版本仍然慢了30倍。 也许幕后有一个ArrayList.toArray()?

因此,请注意代码中不需要的varags方法,并重构以修复长度。 这可能是一种性能提升。

静态参数列表与数组完全不同。 当您以这种方式传递它们时,编译器会为引用保留空间,并在调用方法时填充它们。

Varargs相当于arrays。 要调用此类方法,必须在运行时创建并填充数组。 这就是你观察差异的原因。

String[]String...是同义词。 如果你比较它们,你应该看到相同的性能。

使用最新的JRE6和JRE7,我得到的结果与你的结果不同,它们表明varargs的速度提高了5倍:

 69 69 311 

但是,我不会妄下结论,因为这个基准有几个缺点:函数中没有使用参数; 该function没有做任何事情; 参数具有相同的值。 JIT可以轻松优化此代码和内联函数调用。 我修改了你的例子来解决上面提到的明显问题并得到了以下结果:

 627 7470 7844 

结论是: 不要犹豫使用varargs 。 如果你的函数是微不足道的,那么它的调用由JIT内联,如果不是,那么varargs的开销可能会微不足道。

有趣的问题!

这只是一个猜测:在幕后,Var-args只是数组。 创建这个隐式数组并使用var-args参数填充它可能需要一些时间; 因此性能受到了打击。 好吧,我想。

如上所述,使用var-args时会维护一个数组……

您还应该尝试看到在每个方法的参数中添加“final”的影响

我亲自从2250 – > 2234 ms获得了arrays的改进。