Though this is a really old question, but I want to share some information I earned during my journey.
I could find some explanation about my question on Performance Tips on Android page. First see sample code from the page,
static class Foo {
int mSplat;
}
Foo[] mArray = ...
public void zero() {
int sum = 0;
for (int i = 0; i < mArray.length; ++i) {
sum += mArray[i].mSplat;
}
}
public void one() {
int sum = 0;
Foo[] localArray = mArray;
int len = localArray.length;
for (int i = 0; i < len; ++i) {
sum += localArray[i].mSplat;
}
}
public void two() {
int sum = 0;
for (Foo a : mArray) {
sum += a.mSplat;
}
}
According to the above page, zero() is slowest, one() is faster. Because it pulls everything out into local variables, avoiding the lookups.
I think this explanation might solve my second question, which was asking "a new local variable a
is assigned to hold it. but why?"
I hope this might help someone who have the same curiosity.
[EDIT] Let me add some details about "lookups".
So if you compile above code and disassembles the class file with javap
command with -c option, it will print out disassembled code, i.e., the instructions that comprise the Java bytecodes.
public void zero();
Code:
0: iconst_0 // Push int constant 0
1: istore_1 // Store into local variable 1 (sum=0)
2: iconst_0 // Push int constant 0
3: istore_2 // Store into local variable 2 (i=0)
4: goto 22 // First time through don't increment
7: iload_1
8: aload_0
9: getfield #14 // Field mArray:[LTest$Foo;
12: iload_2
13: aaload
14: getfield #39 // Field Test$Foo.mSplat:I
17: iadd
18: istore_1
19: iinc 2, 1
22: iload_2 // Push value of local variable 2 (i)
23: aload_0 // Push local variable 0 (this)
24: getfield #14 // Field mArray:[LTest$Foo;
27: arraylength // Get length of array
28: if_icmplt 7 // Compare and loop if less than (i < mArray.length)
31: return
public void one();
Code:
0: iconst_0 // Push int constant 0
1: istore_1 // Store into local variable 1 (sum=0)
2: aload_0 // Push this
3: getfield #14 // Field mArray:[LTest$Foo;
6: astore_2 // Store reference into local variable (localArray)
7: aload_2 // Load reference from local variable
8: arraylength // Get length of array
9: istore_3 // Store into local variable 3 (len = mArray.length)
10: iconst_0 // Push int constant 0
11: istore 4 // Store into local variable 4 (i=0)
13: goto 29 // First time through don't increment
16: iload_1
17: aload_2
18: iload 4
20: aaload
21: getfield #39 // Field Test$Foo.mSplat:I
24: iadd
25: istore_1
26: iinc 4, 1
29: iload 4 // Load i from local variable
31: iload_3 // Load len from local variable
32: if_icmplt 16 // // Compare and loop if less than (i < len)
35: return
These instructions are a bit unfamiliar, so I looked up in JVM spec documents. (If you are curious, especially chapter 3, Compiling for the Java Virtual Machine, and chapter 6, The Java Virtual Machine Instruction Set would be helpful).
I added comment to help you understand, but in a nut shell, method zero()
should operate getfield
instruction on every iteration. According to JVM spec documentation 3.8. Working with Class Instances section, getfield
operation performs several jobs like below.
The compiler generates symbolic references to the fields of an instance, which are stored in the run-time constant pool. Those run-time constant pool items are resolved at run-time to determine the location of the field within the referenced object.