跳至主要內容

逃逸分析

AruNi_LuJavaJVM约 1231 字大约 4 分钟

本文内容

前言

在 Java 中,几乎所有的对象都分配在堆上,“几乎” 说明了还是有个别可以不分配到堆上的,那么到底是哪些个别对象呢?这就要涉及到本篇文章要讲的 逃逸分析 了。

1. 什么是逃逸分析?

逃逸分析 其实是 Java 虚拟机中的一种 优化技术,也就是说,它只是一种分析技术,为具体的优化措施提供一种依据

逃逸分析技术的原理是:通过 分析对象的动态作用域,来确定一个对象 在方法中被定义后,是否可能被外部方法所引用(例如该对象作为参数传递到其他方法中)。

其实上面这种判断 是否逃逸到外部方法,叫 方法逃逸,还有一种叫 线程逃逸,即一个对象 可能会被外部线程访问到(例如将对象赋值给其他线程中可以访问的变量)。

而如果通过逃逸分析,能证明一个对象不会逃逸到外部方法,或线程之外(或者说别的方法或线程无法访问到该对象),或者逃逸程度较低(只逃逸出方法,而不逃逸出线程),那么就可以为这个对象采取不同程度的优化,这些优化包括:

  • 栈上分配
  • 标量替换
  • 同步消除

下面就来依次看看这三个优化手段。

2. 栈上分配

如果通过逃逸分析,能确定一个对象 不会逃逸出线程之外,那么就可以让这个对象 分配在栈上,这样对象所占用的空间就会 随着该方法栈帧的出栈而销毁

对象分配在栈上的好处显而易见,可以减少堆中的占用量,从而 节省 GC 操作所消耗的资源。因为 GC 会涉及到筛选可回收对象、整理内存等操作。

3. 标量替换

标量指的是无法分解为更小的数据来表示的数据,例如 int、long。而如果 一个数据可以继续分解,那么就称为聚合量,Java 中的 对象就是典型的聚合量

标量替换指的是把一个对象分解后,将该对象中用到的成员变量恢复为原始类型来访问

如果通过逃逸分析,能确定一个对象 不会逃逸出方法之外,并且其 能被分解,那么程序执行时就可能 不去创建该对象,而是直接 创建它的若干个被使用的成员变量来代替。这样就可以让 该对象的成员变量在栈上分配和读写了

可以看到,标量替换对逃逸程度要求是比较高的,要求不能逃逸出方法之外。

4. 同步消除

学习过并发编程的都知道,线程同步需要消耗的时间是比较多的,因为同步涉及到 CAS、或者加锁的开销。

而如果通过逃逸分析,能确定一个变量 不会逃逸出线程之外,也就是 无法被其他线程访问,那该变量的读写就不会有竞争,所以就可以 不对该变量做任何的同步安全措施,从而大大提高了效率。

5. 总结

逃逸分析 其实是一种分析技术,为具体的优化措施提供一种依据。它通过 分析对象的动态作用域,来确定一个对象 在方法中被定义后,是否可能被外部方法所引用

通过逃逸分析,能证明一个对象不会逃逸到外部方法,或线程之外(或者说别的方法或线程无法访问到该对象),或者逃逸程度较低(只逃逸出方法,而不逃逸出线程),那么就可以为这个对象采取不同程度的优化,这些优化包括:

  • 栈上分配
  • 标量替换
  • 同步消除

其中,栈上分配和标量替换都可以很好的减少对象在堆上的创建,从而减少了堆中 GC 的资源消耗,而 同步消除则是确定了变量是线程安全后,消除对该变量的同步措施,从而提高对该变量的读写效率。

6. 参考文章

  • 《深入理解 Java 虚拟机—第 3 版》
上次编辑于: