Concept is introduced
We all know that objects created in Java are allocated to the heap, but this is not always the case. By analyzing the process of Java object allocation, we can see that there are two places where objects created in Java are not necessarily allocated to the heap. These two points are the escape analysis in Java and the TLAB (Thread Local Allocation Buffer) Thread private cache area.
Introduction to Basic Concepts
Escape analysis is a cross-function global data flow analysis algorithm that can effectively reduce the synchronization load and memory heap allocation pressure in Java programs. Through escape analysis, the Java Hotspot compiler can figure out how far a new object’s references are used to determine whether to allocate the object to the heap.
In the compiler optimization principle of computer language, escape analysis refers to the method of analyzing the dynamic range of pointer, which is related to the pointer analysis and shape analysis of compiler optimization principle. When a variable (or object) is allocated in a method, its pointer may be returned or referenced globally, and thus referenced by other procedures or threads. This phenomenon is called pointer (or reference) Escape. In layman’s terms, an object’s pointer is said to have escaped when it is referenced by multiple methods or threads.
The escape analysis option is supported and enabled by default in Java SE 6U23 and later. Java’s HotSpot JIT compiler can perform escape analysis on code when a method is overloaded or dynamically loaded, while Java objects are allocated on the heap and built-in threads make escape analysis an important feature of Java.
Code sample
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
|
package me.stormma.gc;
/ * *
* <p>Created on 2017/4/21.</p>
*
* @author stormma
*
* @title <p> Escape analysis </p>
* /
public class EscapeAnalysis {
public static B b;
/ * *
* <p> Global variable assignment occurs pointer escape </p>
* /
public void globalVariablePointerEscape() {
b = new B();
}
/ * *
* <p> method returns reference, pointer escape occurs </p>
* @return
* /
public B methodPointerEscape() {
return new B();
}
/ * *
* <p> Instance reference pointer escape </p>
* /
public void instancePassPointerEscape() {
methodPointerEscape().printClassName( this );
}
class B {
public void printClassName(EscapeAnalysis clazz) {
System.out.println(clazz.getClass().getName());
}
}
}
|
What are the benefits of escape analysis research for the Java compiler? We know that Java objects are always allocated in the heap, so the creation and recycling of Java objects can be very expensive to the system. One of the criticisms of the Java language, and one of the reasons for Java’s slow performance, is that Java does not support allocating objects on the stack. The Swing memory and performance bottleneck in JDK6 is due to the GC iterating through the reference tree and reclaiming memory. If the number of objects is large, the GC will be put under a lot of pressure, which indirectly affects performance. Reducing the number of temporary objects allocated in the heap is undoubtedly the most efficient optimization method. In Java application in a widespread scenes, usually in the method, declare a local variable, and the variable in a method implementation life cycle, there was no escape, according to the JVM memory allocation mechanism, first on the heap memory to create instances of the class (object), then press the object reference into the call stack, continue to perform, This is the way the JVM was before optimization. Of course, we can use escape analysis to optimize the JVM. Namely for the redistribution of the stack, first we need to analyze and find the variables did not escape, the variable class instantiation memory allocated in the stack directly, without having to enter the heap, distribution is completed, continue to run the call stack, the last end of the thread, stack space are recycled, local variable object also be recycled, optimization in this way, The main difference lies in the storage medium of the object. The object before optimization is in the heap, while the object after optimization is in the stack, thus reducing the allocation of temporary objects in the heap (time-consuming), thus optimizing the performance.
Performance optimization using escape analysis (-xx :+DoEscapeAnalysis turns on escape analysis)
1
2
3
4
5
6
|
public void method() {
Test test = new Test();
// Process logic
.
test = null ;
}
|
This code can allocate memory on the stack because there is no pointer escape, that is, the reference does not expose the method body.
Stack and heap memory allocation comparison
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
|
package me.stormma.gc;
/ * *
* <p>Created on 2017/4/21.</p>
*
* @author stormma
* @description: <p> Memory allocation comparison </p>
* /
public class EscapeAnalysisTest {
public static void alloc() {
byte [] b = new byte [ 2 ];
b[ 0 ] = 1 ;
}
public static void main(String[] args) {
long b = System.currentTimeMillis();
for ( int i = 0 ; i < 100000000 ; i++) {
alloc();
}
long e = System.currentTimeMillis();
System.out.println(e - b);
}
}
|
The JVM parameter is -server-XMx10m-xMS10M-xx: -doEscapeAnalysis -xx :+PrintGC, and the result is run
The JVM parameter is -server-XMx10m-xMS10m-xx :+DoEscapeAnalysis -xx :+PrintGC, and the result is displayed
The performance test
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
|
package me.stormma.gc;
/ * *
* <p>Created on 2017/4/21.</p>
*
* @author stormma
*
* @description: <p> Performance optimization using escape analysis </p>
* /
public class EscapeAnalysisTest {
private static class Foo {
private int x;
private static int counter;
public Foo() {
x = (++counter);
}
}
public static void main(String[] args) {
long start = System.nanoTime();
for ( int i = 0 ; i < 1000 * 1000 * 10 ; ++i) {
Foo foo = new Foo();
}
long end = System.nanoTime();
System.out.println( "Time cost is " + (end - start));
}
}
|
Optimize JVM output using escape analysis (-server-xx :+DoEscapeAnalysis -xx :+PrintGC)
1
|
Time cost is 11012345
|
Optimized JVM output without escape analysis (-server-XMx10m-xMS10m-xx: -doEscapeAnalysis -xx :+PrintGC)
1
2
3
4
5
|
[GC (Allocation Failure) 33280K->408K(125952K), 0.0010344 secs]
[GC (Allocation Failure) 33688K->424K(125952K), 0.0009799 secs]
[GC (Allocation Failure) 33704K->376K(125952K), 0.0007297 secs]
[GC (Allocation Failure) 33656K->456K(159232K), 0.0014817 secs]
Time cost is 68562263
|
Analysis results, performance optimization 1/6.
From: www.importnew.com/27262.html