Java的varargs性能

Pet*_*Mmm 15 java performance

编码我来检查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) {
    }
}
Run Code Online (Sandbox Code Playgroud)

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

78
4696
78
Run Code Online (Sandbox Code Playgroud)

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

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

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

0
62
0
Run Code Online (Sandbox Code Playgroud)

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

它不是我打算优化的,但我发现这很奇怪......

更新

我添加了一个新测试

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

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

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

Kon*_*rus 19

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

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

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


Ale*_*hov 8

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

69
69
311
Run Code Online (Sandbox Code Playgroud)

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

627
7470
7844
Run Code Online (Sandbox Code Playgroud)

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