Explicit independent vs variable for array performance

I play with Java and want to know how different the following performance metrics are. I understand that premature optimization is a difficult situation in programming, but my curiosity is just for reference in the future.

public class Type1{ int[] data = new data[4]; public int getData( int index ){ return data[index]; } } public class Type2{ int data1; int data2; int data3; int data4; public int getData1(){ return data1; } public int getData2(){ return data2; } public int getData3(){ return data3; } public int getData4(){ return data4; } } 

It is clear that there are many factors that can make a difference, but to some extent there should be some noticeable performance. Obviously, the Type1 class is a much more attractive solution from a design point of view, but it seems that it takes an additional step when retrieving data, namely, it is assembled into an array to get an int as opposing Type2, which just goes right for the data. Perhaps the differences are more noticeable if they contained arrays of class objects, since it would probably be guaranteed that Java uses references for the members of the array. Did I completely leave the ball?

+7
java optimization arrays
source share
2 answers

The difference in runtime between the two approaches is certainly not significant compared to the effect of the difference in API usage.

However, if we reinstall everything so that the API is the same for both, we find that the speed difference at run time is really negligible. The following time code is coming up, and I get ~ 13 seconds for both. Your results may vary.

It might be worth looking at the bytecode to see if the compiler has made the most of the difference more complicated.

 public class Program { public static interface Type { int getData1(); int getData2(); int getData3(); int getData4(); } public static class Type1 implements Type { private int[] data; public Type1(int data1, int data2, int data3, int data4) { data = new int[] { data1, data2, data3, data4 }; } @Override public int getData1() { return data[0]; } @Override public int getData2() { return data[1]; } @Override public int getData3() { return data[2]; } @Override public int getData4() { return data[3]; } } public static class Type2 implements Type { private int data1; private int data2; private int data3; private int data4; public Type2(int data1, int data2, int data3, int data4) { this.data1 = data1; this.data2 = data2; this.data3 = data3; this.data4 = data4; } @Override public int getData1() { return data1; } @Override public int getData2() { return data2; } @Override public int getData3() { return data3; } @Override public int getData4() { return data4; } } public static void main(String[] args) { timeType(new Type1(1, 2, 3, 4)); timeType(new Type2(1, 2, 3, 4)); } private static void timeType(Type type) { long start = System.currentTimeMillis(); int total = 0; for (long i = 0; i < 10000000000l; i++) { total += type.getData1(); total += type.getData2(); total += type.getData3(); total += type.getData4(); } System.out.println(total); System.out.println(System.currentTimeMillis() - start); } } 
+4
source share

No, it is not. Your question is very similar to a problem in JGit implementation:

JGit strives to have no effective way to introduce SHA-1. C can simply say "unsigned char [20]" and include it in the container's memory allocation. A byte [20] in Java will cost an additional 16 bytes of memory, and be slower to access, because the bytes themselves are in a different area of ​​memory from the container object. We try to get around this by going from bytes [20] to 5 tf, but it costs us machine instructions.

From http://marc.info/?l=git&m=124111702609723&w=2

See ObjectId implementation .

Also note that you can provide the Type1 API for Type2 without a (supposedly expensive) indexer:

 public class Type2 { private static final Unsafe U; private static final long data1Offset; static { try { Field f = Unsafe.class.getDeclaredField("theUnsafe"); f.setAccessible(true); U = (Unsafe) f.get(null); Field data1Field = Type2.class.getDeclaredField("data1"); data1Offset = U.objectFieldOffset(data1Field); } catch (Exception e) { throw new RuntimeException(e); } } int data1; int data2; int data3; int data4; public int getData(int index) { assert 0 <= index && index < 4 : "index out of range!"; return U.getInt(this, data1Offset + (index << 2)); } } 
+2
source share

All Articles