Home  >  Article  >  Java  >  Understand JVM escape analysis in 3 minutes

Understand JVM escape analysis in 3 minutes

Java后端技术全栈
Java后端技术全栈forward
2023-08-15 16:39:171221browse

As a qualified Java developer knows, basically all objects are created on the heap. However, there is still no absolute word here, it refers to basically all .

Yesterday during an interview, a friend said that all objects are created in the heap, and then laughed at the interviewer.

Let’s start our text. Let’s talk about escape analysis today.

Escape Analysis (Escape Analysis) is currently a relatively cutting-edge optimization technology in the Java virtual machine. This is a cross-function global data flow analysis algorithm that can effectively reduce synchronization load and memory heap allocation pressure in Java programs. Through escape analysis, the Java Hotspot compiler can analyze the usage range of a new object's reference and decide whether to allocate this object to the heap.

The basic principle of escape analysis is: analyze the dynamic scope of the object. When an object is defined in a method, it may be referenced by an external method, such as being passed as a call parameter to other Among methods, this is called method escape; it may even be accessed by external threads, such as assigning to instance variables that can be accessed in other threads. This is called thread escape; from never escape, method escape to thread escape, It is called the different escape degrees of objects from low to high.

Turn on escape analysis, the compiler can optimize the code as follows:

  1. Synchronous elimination: If an object is found by escape analysis, it can only be Accessed by a thread, the operations on this object can be asynchronous.
  2. Allocation on the stack: If you are sure that an object will not escape from the thread, it would be a very good idea to allocate memory for the object on the stack. The memory space can be destroyed as the stack frame is popped.
  3. Scalar replacement: If an object is found by escape analysis to not be accessed by external methods, and the object can be dismantled, then the object may not be created when the program is actually executed. Instead create it directly using several member variables instead of this method. After splitting the object, the member variables of the object can be allocated and read and written on the stack.

In the JVM, you can specify whether to enable escape analysis through the following parameters:

-XX: DoEscapeAnalysis: Indicates that escape is enabled Analysis (enabled by default after JDK 1.7).

-XX:-DoEscapeAnalysis: Indicates turning off escape analysis.

Synchronization elimination

Thread synchronization itself is a relatively time-consuming process. If escape analysis can determine that a variable will not escape the thread and cannot be used by other Thread access, then there will definitely be no competition in reading and writing this variable, and the synchronization measures implemented on this variable can be safely eliminated.

Such as the following code:

public void method() {
    Object o = new Object();
    synchronized (o) {
        System.out.println(o);
    }
}

Locks the object o, but the life cycle of object o is the same as the method method(), so it will not be accessed by other threads , thread safety issues will not occur, then the JIT compilation phase will be optimized as follows:

public void method() {
    Object o = new Object();
    System.out.println(o);
}

This is also called lock elimination.

Allocation on the stack

In the Java virtual machine, almost all Java programmers know that the memory space for creating objects is allocated on the Java heap. Common sense, objects in the Java heap are shared and visible to each thread. As long as you hold a reference to this object, you can access the object data stored in the heap. The garbage collection subsystem of the virtual machine will recycle objects that are no longer used in the heap, but the recycling action, whether it is marking and filtering out recyclable objects, or recycling and organizing memory, requires a lot of resources. However, there is a special case. If escape analysis confirms that the object will not escape out of the thread, it may be optimized to allocation on the stack. This eliminates the need to allocate memory on the heap and eliminate the need for garbage collection.

Such as the following code:

public static void main(String[] args) throws InterruptedException {

    for (int i = 0; i < 1000000; i++) {
        alloc();
    }

    Thread.sleep(100000);
}

private static void alloc() {
    User user = new User();
}

The code is very simple, it is to create 1 million times in a loop and use the alloc() method to create 1 million User objects. The User object defined in the alloc() method here is not referenced by other methods, so it meets the requirements for allocation on the stack.

The JVM parameters are as follows:

-Xmx2G -Xms2G -XX:+DoEscapeAnalysis -XX:+PrintGCDetails -XX:+HeapDumpOnOutOfMemoryError

Start the program and check the number of instances through the jmap tool:

jmap -histo pid

num     #instances         #bytes  class name
----------------------------------------------
1:          3771        2198552  [B
2:         10617        1722664  [C
3:        104057        1664912  com.miracle.current.lock.StackAllocationTest$User

We can see that the program has created a total of 104057 User objects, which is far less than 100 Ten thousand. We can turn off escape analysis and look at it again:

-Xmx2G -Xms2G -XX:-DoEscapeAnalysis -XX:+PrintGCDetails -XX:+HeapDumpOnOutOfMemoryError

Start the program and check the number of instances through the jmap tool:

jmap -histo 42928

 num     #instances         #bytes  class name
----------------------------------------------
   1:           628       22299176  [I
   2:       1000000       16000000  com.miracle.current.lock.StackAllocationTest$User

You can see that a total of 1 million User objects were created after turning off escape analysis. In comparison, allocation on the stack plays an important role in heap memory consumption and GC.

Scalar replacement

If a data can no longer be decomposed into smaller data to represent, the original data type in the Java virtual machine (numeric types such as int, long and reference types, etc.) cannot be further decomposed, then these data can be called scalars. In contrast, if a piece of data can continue to be decomposed, it is called an aggregate. Objects in Java are typical aggregates.

If escape analysis can prove that an object will not be accessed outside the method, and this object can be dismantled, then when the program is actually executed, it may not create this object, but directly create several of it. Member variables used by this method instead.

has the following code:

public static void main(String[] args) {

    method();
}

private static void method() {
    User user = new User(25);

    System.out.println(user.age);
}

private static class User {

    private int age;

    public User(int age) {
        this.age = age;
    }
}

method()方法中创建User对象,指定age为25,这里User不会被其他方法引用,也就是说它不会逃逸出方法,并且User是可以拆解为标量的。所以alloc()代码会优化为如下:

private static void alloc() {
    int age = 25;

    System.out.println(age);
}

总结

尽管目前逃逸分析技术仍在发展之中,未完全成熟,但它是即时编译器优化技术的一个重要前进方向,在日后的Java虚拟机中,逃逸分析技术肯定会支撑起一系列更实用、有效的优化技术。

The above is the detailed content of Understand JVM escape analysis in 3 minutes. For more information, please follow other related articles on the PHP Chinese website!

Statement:
This article is reproduced at:Java后端技术全栈. If there is any infringement, please contact admin@php.cn delete