I am working with array SomeObject[] someObject = new SomeObject[5000];
.
Each instance inside this array is unique to each other instance but, as a statistical expectation, they require the same computational overhead. In addition the standard deviation of the distribution of computational overhead for each someObject[i]
is very narrow (each someObject[i]
should take 8
- 12
nanoseconds each, mostly clustering around 10
nanoseconds).
What I have noticed is that if I fill this array with the identical instance sharedObject = new SomeObject()
, and loop over SomeObject[]
, it'll be really fast. For example:
SomeObject sharedObject = new SomeObject();
for(int i = 0; i < 5000 ; ++i) {
someObjects[i] = sharedObject;
}
for(int i = 0; i < 5000 ; ++i) {
someObjects[i].doSomething(); //runs really fast.
}
But if I fill the array as:
for(int i = 0; i < 5000 ; ++i) {
someObjects[i] = new SomeObject();
}
for(int i = 0; i < 5000 ; ++i) {
someObjects[i].doSomething(); //runs really slow.
}
then it'll loop over someObject
8 times more slowly, even though each instance has the same computational overhead as each other (within 1 or 2 nanoseconds) when isolated.
Why does this occur and how do I stop this explosion of computational cost occurring?
All computations within each instance of SomeObject
are only over the internal state of that object.
Note that the space on the heap is truly minimal for each new SomeObject()
, so it is not forcing garbage collection.
Here's some code that recreates the problem (but nowhere near as severe as my real life example):
public class Test2 {
public final double random;
public final Double[] sub;
public Test2(double random) {
this.random = random;
sub = new Double[1000];
for(int i = 0 ; i < 1000 ; ++i) {
sub[i] = Math.random();
}
}
public void doSomething() {
for(int i = 0 ; i < 1000 ; ++i) {
double j = (i - 1000)*5*6/4/4/4*sub[i];
}
}
public static void main(String[] args) {
Test2 testFirst = new Test2(Math.random());
Test2[] testFirstArray = new Test2[10000];
Test2[] testSecondArray = new Test2[10000];
for(int i = 0 ; i < 10000 ; ++i) {
testFirstArray[i] = testFirst;
testSecondArray[i] = new Test2(Math.random());
}
//Warmup
for(int i = 0 ; i < 10000 ; ++i) {
testFirstArray[i].doSomething();
testSecondArray[i].doSomething();
}
//Time first class
double firstTimer = System.nanoTime();
for(int i = 0 ; i < 10000 ; ++i) {
testFirstArray[i].doSomething();
}
System.out.println((System.nanoTime() - firstTimer)/(1000*1000));
//Time second class
double secondTimer = System.nanoTime();
for(int i = 0 ; i < 10000 ; ++i) {
testSecondArray[i].doSomething();
}
System.out.println((System.nanoTime() - secondTimer)/(1000*1000));
}
}