It is generally believed that the objects that are new are all allocated on the heap, but this is not completely correct. Through the analysis of the Java object allocation process, we found that in addition to being allocated on the heap, objects can also allocate space in the stack or TLAB. The technical basis for allocating objects on the stack is escape analysis and scalar replacement. This article mainly introduces escape analysis.
Definition of escape analysis
Escape analysis is a cross-functional global data flow analysis algorithm that can effectively reduce the synchronous load and memory heap allocation pressure in Java programs.
Through escape analysis, the Java Hotspot compiler can analyze the scope of use of a new object's reference and determine whether to allocate the object to the heap.
Java supports and enables escape analysis options in Java SE 6u23 and later versions. Java's HotSpot JIT compiler can perform escape analysis of the code when the method is overloaded or dynamically loaded.
The basic behavior of escape analysis is to analyze the dynamic scope of an object: when an object is defined in a method, it may be referenced by an external method.
Method escape: For example, pass as a call parameter to other methods.
Thread escape: It may be accessed by external threads, such as assigning to class variables or instance variables that can be accessed in other threads.
Theoretical basis of escape analysis
Escape analysis is performed based on the algorithm described by Jong-Deok Choi, Manish Gupta, Mauricio Seffano, Vugramam C. Sreedhar, Sam Midkiff and others in the paper "Escape Analysis for Java".
This algorithm introduces a connected graph, uses the connected graph to construct the accessible relationship between object and object reference, and proposes a combined data flow analysis method based on the second basis. Since the algorithm is context-dependent and stream-sensitive, and simulates nested relationships at any level of the object, the analysis accuracy is high, but the run time and memory consumption are relatively large.
Most implementations of escape analysis are based on the premise of "closed world": all possible methods that are executed have been known before the escape analysis, and the actual operation of the program will not change the call relationship between them. But when a real Java program runs, such assumptions do not hold true. Many features of Java programs, such as dynamic class loading, calling local functions, and reflecting program calls, will break the so-called "closed world" convention.
Processing operations after escape analysis
After escape analysis, three possible escape states of the object can be obtained:
GlobalEscape: that is, the reference of an object escapes a method or thread. For example, an object's reference is copied to a class variable, or stored in an object that has escaped, or the object's reference is returned to the calling method as the return value of the method.
ArgEscape (parameter level escape): that is, the application of the object passed to a method during the method call process. This state can be determined by analyzing the binary code of the method being tuned.
NoEscape: An object that can be replaced by scalars. The object may not be allocated on a traditional heap.
The compiler can use the results of escape analysis to optimize the program:
The heap allocation object becomes a stack allocation object: an object in a method, and the object reference does not escape, so this method may be allocated on the stack memory and is very common to heap memory.
Eliminate synchronization: The cost of thread synchronization is quite high, and the consequences of synchronization are reduced concurrency and performance. Escape analysis can determine whether an object is always accessed by only one thread. If it is accessed by only one thread, the synchronization operation of the object can be converted into an operation without synchronization protection, which can greatly improve the degree of concurrency and performance.
Vector substitution: Escape analysis method If you find that the memory storage structure of the object does not need to be carried out continuously, you can save parts and even all of the object in the CPU registers, which can greatly improve access speed.