Objects in Java can be unallocated in the heap because of on-stack allocation, synchronous elision, and scalar substitution

All three techniques require the use of escape analysis

Escape analysis is a cross-function global data flow analysis algorithm that can effectively reduce synchronization load and heap allocation pressure in Java programs.

When an object is defined in a method and is only used inside the method, no escape is considered to have occurred. An escape is considered to have occurred if an object is referenced by an external object. Through escape analysis, the HotSpot compiler can figure out the usage range of a new object and decide whether or not to allocate it to the heap.

An instance that has not escaped:

void m(a){
    //obj is only used in the method, no escape occurs
    Object obj = new Object();
}
Copy the code

Escape example:

Object m(a){
	Object obj = new Object();
	return obj;// The object may be referenced by an external object and escape has occurred
}
Copy the code

On the stack

The stack assigned to refers to is the stack frame corresponding to the Java method.

Objects that do not escape may be optimally allocated to the stack because stack space is removed as the method completes execution.

In JDK6, HotSpot already has escape analysis enabled by default. You can also use -xx :+DoEscapeAnalysis to show escape analysis enabled, and -xx :+PrintEscapeAnalysis to view the filter results of escape analysis.

So in development, if you can use local variables, don’t define them outside the method.

Synchronous omit

If an object is found to be accessible only from one thread, operations on the object can be performed without regard to synchronization.

When a block of synchronized code is compiled dynamically, the JIT compiler uses escape analysis to determine whether the lock object being used can only be accessed by one thread and not distributed to other threads. If not, the JIT compiler unsynchronizes that part of the code when the block is compiled. This process is also called lock elimination

Example code is as follows:

void m(a){
	Object lockObj = new Object();
    synchronized(lockObj){
        // The lockObj object, which can only be accessed in the current thread, will be unsynchronized.
        System.out.print("hello"); }}Copy the code

The final code

void m(a){
	Object lockObj = new Object();
    System.out.print("hello");// The lock is removed
}
Copy the code

Scalar replacement

Scalar substitution is also called separating objects

A scalar is a piece of data that cannot be decomposed. The basic data type in Java is a scalar, and the corresponding, such as a Java object, is an aggregate that can be decomposed. During JIT compilation, if an object is found to be inaccessible by escape analysis, the object is split into several containing member variables instead.

Some objects may be accessible without needing to exist as a continuous memory structure, so parts (or all) of the object may not be stored in memory, but in CPU registers.

You can turn on scalar substituting (on by default), allowing objects to be scattered on the stack, with -xx :+EliminateAllocations.

Example code is as follows:

class Location {
    int x;
    int y;
}

void m(a){
    Location loc = new Location();
    loc.x = 1;
    loc.y = 2;
    System.out.print("x:"+loc.x+",y:"+loc.y);
}
Copy the code

Final code:

void m(a){
    int x = 1;
    int y = 2;
    System.out.print("x:"+x+",y:"+y);
}
Copy the code

Existing problems

Escape analysis itself requires a series of complex analysis, which is expensive and cannot guarantee positive optimization. If, after analysis, it is found that all objects do not escape, then the analysis process is wasted. So stack allocation is not used in HotSpot, so it is clear that all object instances are created on the heap.

conclusion

Java object instances are allocated on the heap