Skip to content
文章目录

1、逃逸分析

1.1、什么是逃逸分析?

就是分析对象动态作用域,当一个对象在方法中被定义后,它可能被外部方法所引用,例如作为调用参数传递到其他地方中。

1.2、逃逸分析种类

  • 全局变量赋值逃逸
    • 赋值给类变量或者可以在其他线程中访问的实例变量
  • 方法返回值逃逸
  • 实例引用逃逸
  • 线程逃逸
java
package com.imooc.jvm.jvm;

class EscapeTest1 {
    public static SomeClass someClass;

    // 全局变量赋值逃逸
    public void globalVariablePointerEscape() {
        someClass = new SomeClass();
    }

    // 方法返回值逃逸
    // someMethod(){
    //   SomeClass someClass = methodPointerEscape();
    // }
    public SomeClass methodPointerEscape() {
        return new SomeClass();
    }

    // 实例引用传递逃逸
    public void instancePassPointerEscape() {
        this.methodPointerEscape()
            .printClassName(this);
    }
}

class SomeClass {
    public void printClassName(EscapeTest1 escapeTest1) {
        System.out.println(escapeTest1.getClass().getName());
    }
}

1.3、逃逸状态标记

全局级别逃逸:一个对象可能从方法或者当前线程中逃逸

  • 对象被作为方法的返回值
  • 对象作为静态字段( static field)或者成员变量(field)
  • 如果重写了某个类的 finalize()方法,那么这个类的对象都会被标记为全局逃逸状态并且一定会放在堆内存中。

参数级别逃逸

  • 对象被作为参数传递给一个方法,但是在这个方法之外无法访问/对其他线程不可见。

无逃逸:

  • 一个对象不会逃逸。

2、标量替换

2.1、标量

  • 不能被进一步分解的量
    • 基础数据类型
    • 对象引用

2.2、聚合量

  • 可以进一步分解的量

2.3、标量替换

  • 通过逃逸分析确定该对象不会被外部访问,并且对象可以被进一步分解时,JVM不会创建该对象,而是创建它的成员变量来代替。-XX:+EliminateAllocations开启标量替换(JDK8默认开启)
java
public void someTest() {
    SomeTest someTest = new SomeTest();
    someTest.age = 1;
    someTest.id = 1;

    // 开启标量替换之后,
    int age = 1;
    int id = 1;
}

class SomeTest {
    int id;
    int age;
}

3、栈上分配

  • 通过逃逸分析,能够确定对象不会被外部访问,就在栈上分配对象

4、相关JVM参数

参数默认值(JDK 8)作用
-XX:+DoEscapeAnalysis开启是否开启逃逸分析
-XX:+EliminateAllocations开启是否开启标量替换
-XX:+EliminateLocks开启是否开启锁消除