Autoboxing performance
Asked Answered
T

7

6

Why groups j=k*l and m=n*o have different performance, while first 3 groups have the same ?

int a = 42;
int b = 42;
int c = 42;

Integer d = 42;
int e = 42;
int f = 42;

int g = 42;
Integer h = 42;
int i = 42;

int j = 42;
int k = 42;
Integer l = 42;

Integer m = 42;
Integer n = 42;
Integer o = 42;

for(int z = 0; z < 1000000000; z++){
    // c = a*b; // 630 ms
    // f = d*e; // 630 ms
    // i = g*h; // 630 ms
    // l = j*k; // 6000 ms
    // o = m*n; // 6400 ms
}
Triplicity answered 28/1, 2013 at 8:17 Comment(0)
A
6

You have a loop which doesn't do anything useful. As such the JIT can take some time to detect this and eliminate the loop. In the first four examples, the code is taking an average of a fraction of a clock cycle. This is a strong hint that the loop has been optimised away and you are actually measuring how long it takes to detect and replace the loop with nothing,

In the later examples, the loop is not optimised away because there is something about the loop which the JIT doesn't eliminate. I suspected it was the object allocation for the Integer but -verbosegc showed that no objects were being created.

On my machine the loop take about 1.9 ns or about 6 clock cycles which is pretty quick so I am not sure what is left which takes that much time..

Albaalbacete answered 28/1, 2013 at 8:27 Comment(1)
I'm just wondering about this modification, does it still eliminate the loop? (or, similarly, I would like to see the time results of an example where the loop isn't eliminated) (results obtained with Java 1.6.0_37)Pronominal
A
4

Creating a new object in a cycle always has a cost. In the last two examples you created new Integer objects in the cycle what has high performance cost. Primitives are stored in stack, objects are in heap. Putting something into stack is cheaper than into heap.

Agonist answered 28/1, 2013 at 8:21 Comment(2)
You should add, that 42*42 > 127, so there will be a new object created each iteration. If he used 10*10, precached objects would have been used.Elbowroom
If you run with -verbosegc on Java 7 update 10 it doesn't create any objects (or not enough to trigger a GC)Albaalbacete
O
4

Basically this is what happening inside JVM and thats causing performance issue.

c = a*b; // 630  ms -> No boxing and unboxing
f = d*e; // 630  ms -> Unboxing d
i = g*h; // 630  ms -> Unboxing h
l = j*k; // 6000 ms -> Creates a new Integer object L, and assign J * K to L
o = m*n; // 6400 ms -> Creates a new Integer object 0, unbox m and n for calculation and assign m * n to o

In other words

l = j*k; // 6000 ms is equivalent to below code

temp = j*k;
Integer l = new Integer(temp); 

o = m*n; // 6400 ms is equivalent to below code

temp = j.intValue() * k.intValue();
Integer l = new Integer(temp); 

Your last two statements will create around 1000000000 (loop count) unnecessary Integer object. Which will be obviously a performance slog.

Owenowena answered 28/1, 2013 at 8:32 Comment(4)
So, if f = d*e was not optimized, it would be more costly than c = a*b ?Triplicity
Its equivalent to f = d.intValue() * e. If you see the intValue() source code it will Just send you the value. So ideally there should not be any performance issue there.Owenowena
But it has to unbox the value like in o=m*n which is more costly. I figured that first 3 groups are optimized, so they yield same result and 2 last groups are not, so there is performance difference due to unboxing.Triplicity
Am not saying both are equal it will have o=m*n difference. But the difference is intValue() method. Which will not take much time for processing. Because it just returns a value and does no other processing.Owenowena
R
1
  1. Integer autobox has a small cache
  2. Creating an object costs a litter time

check this: java.lang.Integer.IntegerCache

Rissole answered 28/1, 2013 at 8:24 Comment(0)
E
0

Probably because l = j * k needs to box an int to an Integer, whereas c = a * b doesn't need to. The VM could also optimize the loop, understanding that executing a single iteration would lead to the same result as executing 1 billion. Beware of simplistic micro-benchmarks.

Eckert answered 28/1, 2013 at 8:22 Comment(0)
H
0
m = n*o  ==> Integer = Integer * Integer 

while:

l = j*k ==> Integer = int * int // Integer is an object so autoboxing costs some performance here.
Hexyl answered 28/1, 2013 at 8:23 Comment(7)
The first one has to auto-box just as such as the second.Albaalbacete
Guess the compile optimizes the 1st one that it doesnt use the wrapper but the underlying primptive datatye (int) as all variables of the same type (Integer), while the second has to work on two stages, once primptive (int * int) then autoboxing (int => Integer).Hexyl
If you run with -verbosegc you can see that no wrappers are being created. ;)Albaalbacete
The Integer is a wrapper object, doesnt it need to be created??Hexyl
Not if it's optimised away e.g. because it's not used.Albaalbacete
where isnt it created in the 1st one(m = no), or in the second one (l = jk)Hexyl
None of the examples end up creating objects once they have been optimised by the JIT.Albaalbacete
P
0

Creating an object has an overhead (or, from other comments, it appears that it might be that, when creating an object, the loop can't optimised away because nothing is being done inside it).

int = int * int

No objects involved.

int = Integer * int or int = int * Integer

The Integer's int member get multiplied with the int, and no objects need to be created.

Integer = int * int

An Integer object needs to be created from the result (slow).

Integer = Integer * Integer

The two Integer's int members get multiplied, but then an Integer object needs to be created from the result (slow).

Pronominal answered 28/1, 2013 at 8:27 Comment(0)

© 2022 - 2024 — McMap. All rights reserved.