introduction
In the process of interviewing others, the JVM memory model almost needs to be asked, although some people say that these are the interview to build an aircraft carrier and screw up the work. If you want to be a CRUD coder, you can choose not to know this.
In the question and answer of JVM memory model, some people can say that objects are allocated on the heap. But when I asked that objects must be stored on the heap, most people answered yes or hesitated.
In fact, it is correct to answer that the object is allocated storage on the heap. However, with the development of JIT real-time compiler and the gradual maturity of escape analysis technology, the allocation of all objects to the heap has gradually become less absolute. There will be some subtle changes in optimization techniques such as on stack allocation, scalar substitution and lock elimination.
We know that the Java source code we write is compiled into a bytecode file through javac, and then the class loader loads the bytecode file into memory. The JVM reads and interprets the bytecode line by line and translates it into the corresponding machine instructions for execution. Obviously, interpretation execution is much slower than those binary programs that can be executed directly (such as C language programs).
Therefore, in order to improve efficiency, JIT (just in time compiler) optimization technology is introduced. Java programs will still be interpreted and executed through the interpreter, but if a method or code block runs frequently, the JVM considers it a hot code, then translates the hot code into local machine instructions, optimizes and caches it, and runs it directly the next time it runs this code without interpretation.
Escape Analysis is a very important optimization technology in JIT.
escape analysis
Escape analysis is to analyze whether an object will escape from the method and the dynamic scope of the object. If an object is defined within a method and may be used by external references to the method, it is considered to have escaped.
For example, the following person object escapes, that is, it may be referenced externally by the method.
public Person personEscape() { Person person = new Person(); return person; }
Therefore, the ultimate purpose of escape analysis is to optimize the program and improve the running performance. There are the following optimization technical points:
- On stack allocation
- scalar replacement
- Lock elimination
JDK1.7. At the beginning, escape analysis is enabled by default, and can be started and stopped through the following parameters.
# open -XX:+DoEscapeAnalysis # close -XX:-DoEscapeAnalysis
On stack allocation
If an object does not escape from the method, it may be allocated to the stack. This eliminates the need for GC recycling in the heap and improves performance.
package com.chenpi; /** * @Description * @Author dried tangerine peel * @Date 2021/7/14 * @Version 1.0 */ public class EscapeAnalysisTest { public static void main(String[] args) { long startTime = System.currentTimeMillis(); for (int i = 0; i < 10000000; i++) { stackAlloc(); } System.out.println((System.currentTimeMillis() - startTime) + "ms"); } public static void stackAlloc() { Person person = new Person("dried tangerine peel", 18); } } class Person { private String name; private long age; public Person(String name, long age) { this.name = name; this.age = age; } }
Virtual machine parameter settings enable escape analysis and print GC logs.
-Xms200m -Xmx200m -XX:+DoEscapeAnalysis -XX:+PrintGC
The results of running the program are as follows: the consumption takes only 10 ms and there is no GC.
10ms
Turn off escape analysis and print the GC log.
-Xms200m -Xmx200m -XX:-DoEscapeAnalysis -XX:+PrintGC
The results of running the program are as follows: the consumption time increases more than 10 times, accompanied by multiple GC.
[GC (Allocation Failure) 51712K->784K(196608K), 0.0050396 secs] [GC (Allocation Failure) 52496K->784K(196608K), 0.0030730 secs] [GC (Allocation Failure) 52496K->752K(196608K), 0.0013993 secs] [GC (Allocation Failure) 52464K->720K(196608K), 0.0018371 secs] 176ms
scalar replacement
- Scalar: it cannot be decomposed into smaller data types. For example, the basic data type is scalar.
- Aggregate quantity: it can be decomposed into other aggregate quantities or scalar data types, such as object reference types.
If an object does not escape, JIT can optimize to decompose the object into several scalars instead. This is scalar substitution.
public void scalarReplace() { Coordinates coordinates = new Coordinates(105.10, 80.22); System.out.println(coordinates.longitude); System.out.println(coordinates.latitude); }
In the above demonstration program, the coordinates object will not escape, so the JIT compiler can use scalar substitution for optimization. Finally, it is optimized into the following program.
public void scalarReplace() { System.out.println(105.10); System.out.println(80.22); }
In fact, in the existing virtual machine, there is no real allocation on the stack, which is actually realized by scalar replacement.
Lock elimination
Why eliminate locks? Because locking will reduce performance, how not to lock is the best. If it is analyzed that the locked object will not escape, that is, it can only be accessed by one thread, JIT can optimize and eliminate the lock. Also known as synchronous ellipsis.
public void lockRemove() { synchronized (new Object()) { System.out.println("I'm tangerine peel!"); } }
In the above demo program, the Object object will not escape, so it can only be accessed by the current thread, so the JIT compiler can optimize and eliminate the lock. Finally, it is optimized into the following program.
public void lockRemove() { System.out.println("I'm tangerine peel!"); }
summary
However, with the development of JIT real-time compiler and the gradual maturity of escape analysis technology, the allocation of all objects to the heap has gradually become less absolute. Through escape analysis technology, objects may be allocated to the stack, which can reduce GC and improve program performance.
But is the performance of the program with escape analysis enabled higher than that without escape analysis enabled? Not necessarily. In fact, the escape analysis technology is also very complex, so it is also a time-consuming process. If it is found that all objects escape after escape analysis, it cannot be optimized, then the process of escape analysis consumes time, does not play an optimization role, and the gain is not compensated.