概述
逃逸分析,就是分析变量能不能逃出它的作用域;
标量替换和栈上分配,则是基于逃逸分析的前提下去做的。
一、逃逸分析
1、是什么
逃逸分析:指的是分析变量能否逃出它的作用域
可以细分为4种场景
1)全局变量赋值逃逸
代码示例
public class EscapeTest{
public static SomeClass someClass;
public void globalVariablePointerEscape(){
// 全局变量逃逸
someClass = new SomeClass();
}
}
class SomeClass{
}
2)方法返回值逃逸
代码示例
public class EscapeTest{
public SomeClass methodPointerEscape(){
// 方法返回值逃逸
return new SomeClass();
}
}
class SomeClass{
}
3)实例引用逃逸
代码示例
public class EscapeTest{
public SomeClass methodPointerEscape(){
return new SomeClass();
}
public void instancePassPointerEscape(){
// 实例引用逃逸
this.methodPointerEscape().print(this);
}
}
class SomeClass{
public void print(EscapeTest escapeTest){
System.out.println(escapeTest);
}
}
4)线程逃逸
赋值给类变量或可以在其他线程中访问的实例变量。
代码示例:略
2、逃逸状态标记
分为3中逃逸状态标记
1)全局级别逃逸
一个对象可能从方法或当前线程中逃逸,也就是说,其他的方法和其他的线程也能访问到这个对象。
主要有以下场景:
a、对象最为返回值返回。;
b、对象作为静态字段(static field)或者成员变量(field)
c、如果重写了某个类的finalize()方法,那么这个类的对象都会被标记为全局逃逸状态并且一定会放在堆内存中。
2)参数级别逃逸
对象被作为参树传递给一个方法,但是在这个方法之外无法访问/对其他线程不可见。
3)无逃逸
一个对象不会逃逸。
3、如何控制
-XX:+DoEscapeAnalysis 开启逃逸分析(JDK8默认开启)
-XX:+DoEscapeAnalysis 关闭逃逸分析
二、标量替换
1、是什么
**标量:**指的是java中不能进一步分解的量,比如8大基本类型;
**聚合量:**于标量相对,指的是不能进一步分解的量,如String。
**标量替换:**通过逃逸分析确定该对象不会被外部访问,并且对象可以被进一步分解时,JVM不会创建该对象,而是创建它的成员变量来代替
2、作用
标量一会可以节省创建对象需要的内存空间。
3、如何控制
-XX:+EliminateAllocations 开启标量替换(JDK8默认开启)
-XX:-EliminateAllocations 关闭标量替换
三、栈上分配
1、是什么
我们知道,java中绝大对数对象是存放在堆中的,当对象没用的时候,靠垃圾回收器去回收对象;
栈上分配指的是,如果通过逃逸分析,确定对象不会被外部访问,就在栈上分配对象。
2、作用
在栈上分配对象,那么这个对象就会在栈帧出栈的时候被销毁了,因而通过栈上分配,可以降低垃圾回收的压力。
3、如何控制
JVM自动实现