编码我来检查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...是同义词.如果您比较它们,您应该看到相同的性能.
使用最新的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的开销可能会微不足道.
| 归档时间: |
|
| 查看次数: |
5093 次 |
| 最近记录: |