my code is here =>
class PointHolder {
private Point point;
public PointHolder(Point point) {
this.point = point;
}
//getter
}
class Point {
private int x;
private int y;
public Point(int x, int y) {
this.x = x;
this.y = y;
}
//getter setter
}
public class Escape {
public static void main(String[] args) {
for (int i = 0; i < 20000; i++) {
test4(i);
}
}
static int foo;
public static void test4(int x) {
PointHolder pointHolder = new PointHolder(new Point(x + 2, 42));
foo = pointHolder.getPoint().getX();
}
}
use the jitwatch, i could see the pointHolder is not been allocated, but new Point(x+2, 42)
is still been allocated.
i could not figure out why
Escape Analysis in HotSpot C2 compiler is rather simple. It never attempted to detect all possible objects that do not escape the compilation scope. In particular, it does not currently handle a multi-level reference tree.
In your example, a reference to a newly allocated Point
is assigned to an object field: PointHolder.point
. JIT treats this assignment as an escape of Point
object and thus does not eliminate the allocation.
One particular exception is boxing-unboxing: HotSpot handles boxing-unboxing methods specially. E.g. it would be still able to eliminate allocation of Integer
object when it is assigned to an IntegerHolder
field.
This problem is not something unsolvable though - it's rather a missed optimization opportunity. Graal JIT is better in this sence - in the given example it does eliminate both Point
and PointHolder
allocations.