调用数组的开销是多少。

2022-08-31 16:04:09

在将 for 循环更新为应用程序中的每个循环时,我遇到了很多这样的“模式”:

for (int i = 0, n = a.length; i < n; i++) {
    ...
}

而不是

for (int i = 0; i < a.length; i++) {
    ...
}

我可以看到您获得了集合的性能,因为您不需要在每个循环中调用size()方法。但是用数组??

所以问题出现了:比常规变量更昂贵吗?array.length


答案 1

否,调用 is 或 常量时间操作。array.lengthO(1)

由于 is(作用类似于)的成员,因此访问速度并不比局部变量慢。(这与调用像这样的方法非常不同.lengthpublicfinalarraysize())

无论如何,现代JIT编译器都可能优化调用以纠正。.length

您可以通过查看 OpenJDK 中 JIT 编译器的源代码,或者让 JVM 转储 JIT 编译的本机代码并检查代码来确认这一点。

请注意,在某些情况下,JIT编译器可能无法执行此操作;例如:

  1. 如果要调试封闭方法,或者
  2. 如果循环体具有足够的局部变量来强制寄存器溢出。

答案 2

我在午餐时有一点时间:

public static void main(String[] args) {
    final int[] a = new int[250000000];
    long t;

    for (int j = 0; j < 10; j++) {
        t = System.currentTimeMillis();
        for (int i = 0, n = a.length; i < n; i++) { int x = a[i]; }
        System.out.println("n = a.length: " + (System.currentTimeMillis() - t));

        t = System.currentTimeMillis();
        for (int i = 0; i < a.length; i++) { int x = a[i]; }
        System.out.println("i < a.length: " + (System.currentTimeMillis() - t));
    }
}

结果:

n = a.length: 672
i < a.length: 516
n = a.length: 640
i < a.length: 516
n = a.length: 656
i < a.length: 516
n = a.length: 656
i < a.length: 516
n = a.length: 640
i < a.length: 532
n = a.length: 640
i < a.length: 531
n = a.length: 641
i < a.length: 516
n = a.length: 656
i < a.length: 531
n = a.length: 656
i < a.length: 516
n = a.length: 656
i < a.length: 516

笔记:

  1. 如果你逆转测试,那么显示比大约一半快,可能是由于垃圾回收(?)。n = a.lengthi < a.length
  2. 我不能做得更大,因为我得到了.250000000OutOfMemoryError270000000

关键是,这是其他人一直在做的,你必须在内存中运行Java,你仍然看不到两种选择之间在速度上的显着差异。将开发时间花在真正重要的事情上。