✅什么是逃逸分析?

典型回答

逃逸分析是Java HotSpot Server编译器中JIT优化的一个重要步骤。它在Java SE 6u23及以后的版本中默认启用。

✅简单介绍一下JIT优化技术?

对象基于逃逸分析可以有三种状态:全局逃逸(GlobalEscape)、参数逃逸(ArgEscape)和无逃逸(NoEscape)。

  1. 全局逃逸(GlobalEscape):对象超出了方法或线程的范围,比如被存储在静态字段或作为方法的返回值。
public class GlobalEscapeExample {
    private static Object staticObject;

    public void globalEscape() {
        staticObject = new Object(); // 这个对象赋值给静态字段,因此它是全局逃逸的
    }
}

public static StringBuffer craeteStringBuffer(String s1, String s2) {
    StringBuffer sb = new StringBuffer();
    sb.append(s1);
    sb.append(s2);
    return sb;
}

如我们新建的staticObject就是全局逃逸的。以及下面的方法中的sb对象,也是全局逃逸的。

  1. 参数逃逸(ArgEscape):对象被作为参数传递或被参数引用,但在方法调用期间不会全局逃逸。
public class ArgEscapeExample {
    public void methodA() {
        Object localObject = new Object();
        methodB(localObject); // localObject作为参数传递,但不会从methodB中逃逸
    }

    public void methodB(Object param) {
        // 在这里使用param
    }
}

如传递到methodB中的param对象,就是发生了参数逃逸的。因为他从methodA中逃逸到了methodB中。

  1. 无逃逸(NoEscape):对象可以被标量替换,意味着它的内存分配可以从生成的代码中移除。
public static String createStringBuffer(String s1, String s2) {
    StringBuffer sb = new StringBuffer();
    sb.append(s1);
    sb.append(s2);
    return sb.toString();
}

如上面的sb,就没有发生逃逸,因为这个对象本身没有作为参数传递,也没有被当做方法返回值,并没有赋值给静态变量。

在Java中,不同的逃逸状态影响JIT(即时编译器)的优化策略:

  1. 全局逃逸(GlobalEscape):由于对象可能被多个线程访问,全局逃逸的对象一般不适合进行栈上分配或其他内存优化。但JIT可能会进行其他类型的优化,如方法内联或循环优化。(方法内联参考:https://www.yuque.com/hollis666/xkm7k3/nkr4ge#ovn99
  2. 参数逃逸(ArgEscape):这种情况下,对象虽然作为参数传递,但不会被方法外部的代码使用。JIT可以对这些对象进行一些优化,例如锁消除
  3. 无逃逸(NoEscape):这是最适合优化的情况。JIT可以采取多种优化措施,如在栈上分配内存,消除锁,甚至完全消除对象分配(标量替换)。这些优化可以显著提高性能,减少垃圾收集的压力。
优化手段 全局逃逸 参数逃逸 无逃逸
方法内联 Y Y Y
循环优化 Y Y Y
锁消除 N Y Y
栈上分配 N N Y

总的来说,JIT编译器根据对象的逃逸状态采用不同的优化策略,以提高Java程序的性能和效率。

扩展知识

开启逃逸分析

在Java代码运行时,通过JVM参数可指定是否开启逃逸分析,

-XX:+DoEscapeAnalysis: 表示开启逃逸分析

-XX:-DoEscapeAnalysis : 表示关闭逃逸分析 从jdk 1.7开始已经默认开始逃逸分析,如需关闭,需要指定-XX:-DoEscapeAnalysis

逃逸分析并不成熟

关于逃逸分析的论文在1999年就已经发表了,但直到JDK 1.6才有实现,而且这项技术到如今也并不是十分成熟的。

其根本原因就是无法保证逃逸分析的性能消耗一定能高于他的消耗。虽然经过逃逸分析可以做标量替换、栈上分配、和锁消除。但是逃逸分析自身也是需要进行一系列复杂的分析的,这其实也是一个相对耗时的过程。

一个极端的例子,就是经过逃逸分析之后,发现没有一个对象是不逃逸的。那这个逃逸分析的过程就白白浪费掉了。

虽然这项技术并不十分成熟,但是他也是即时编译器优化技术中一个十分重要的手段。

原文: https://www.yuque.com/hollis666/xkm7k3/vwrawt9lig6whl4o