What is the Cost of Calling array.length

北战南征 提交于 2019-11-26 02:07:22
jjnguy

No, a call to array.length is O(1) or constant time operation.

Since the .length is(acts like) a public final member of array, it is no slower to access than a local variable. (It is very different from a call to a method like size())

A modern JIT compiler is likely to optimize the call to .length right out anyway.

You can confirm this by either looking at the source code of the JIT compiler in OpenJDK, or by getting the JVM to dump out the JIT compiled native code and examining the code.

Note that there may be cases where the JIT compiler can't do this; e.g.

  1. if you are debugging the enclosing method, or
  2. if the loop body has enough local variables to force register spilling.

I had a bit of time over lunch:

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));
    }
}

The results:

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

Notes:

  1. If you reverse the tests, then n = a.length shows as being faster than i < a.length by about half, probably due to garbage collection(?).
  2. I couldn't make 250000000 much larger because I got OutOfMemoryError at 270000000.

The point is, and it is the one everyone else has been making, you have to run Java out of memory and you still don't see a significant difference in speed between the two alternatives. Spend your development time on things that actually matter.

I doubt there is any significant difference whatsoever, and even if there was, I would bet it's probably optimized away during compilation. You're wasting your time when you try to micro-optimize things like that. Make the code readable and correct first, then if you have a performance problem, use a profiler, then worry about choosing better data structures/algorithms if appropriate, then worry about optimizing the parts your profiler highlights.

The length of an array is stored as a member variable of the array (not the same as an element) in Java, so fetching that length is a constant time operation, the same as reading a member variable from a regular class. Many older languages like C and C++ don't store the length as part of the array, so you'd want to store the length before the loop starts. You don't have to do that in Java.

In that case, why don't you make an inverse loop:

for (int i = a.length - 1; i >= 0; --i) {
    ...
}

There are 2 micro optimizations here:

  • Loop reversal
  • Postfix decrement

It might be ever-so-slightly faster to store it in a variable. But I would be extremely surprised if a profiler pointed to it as being a problem.

At the bytecode level, getting the length of an array is done with the arraylength bytecode. I don't know if it is slower than an iload bytecode, but there shouldn't be enough difference to notice.

Michael Burr

This answer is from a C# point of view, but I would think the same applies to Java.

In C#, the idiom

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

is recognized as iterating over the array, so the bounds check is avoided when accessing the array in the loop instead of with each array access.

This may or may not be recognized with code such as:

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

or

n = a.length;

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

How much of this optimization is performed by the compiler vs. the JITter I don't know, and in particular if it's performed by the JITter I'd expect all 3 to generate the same native code.

However, the first form is also arguably more readable by people, so I'd say go with that.

Array.length is a constant and the JIT compiler should see through that in both instances. I would expect the resulting machine code to be the same in both cases. At least for the server compiler.

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!