jvm|JVM底层原理之什么是逃逸分析

jvm|JVM底层原理之什么是逃逸分析

JVM底层原理之什么是逃逸分析
介绍:
逃逸分析(Escape Analysis)根据运行状态可以判断方法中的变量 , 是否会被外部方法引用或外部线程访问 , 如果会 , 那么这个行为就是逃逸 , 根据情况可以分为两种逃逸:
方法逃逸
当一个方法中的变量可能被外部方法所引用 , 比方说作为调用参数 , 将其传递到其他的子方法中 , 这种可以称为方法逃逸 。
【jvm|JVM底层原理之什么是逃逸分析】线程逃逸
如果是多线程环境 , 有的变量没有作线程保护 , 可能会被外部线程访问到 , 这种行为称为线程逃逸 。
也就是这项技术并不是什么优化技术 , 而是进行某些专项优化前的必要分析 , 如果不会发生逃逸现象 , 才进行一些专项的优化 。 另外这项技术是从JDK1.6开始的 , 所以目前而言不算太成熟 , 因为逃逸分析需要一些复杂的运算 , 又要兼顾性能的损耗 , 所以会有一些误差 。
参数设置:
可以通过JVM参数进行设置开启或关闭逃逸分析:
-XX:+DoEscapeAnalysis 开启逃逸分析(jdk1.8 默认开启)-XX:-DoEscapeAnalysis 关闭逃逸分析

它手下的优化方法主要有三种:栈上分配锁消除标量替换 。 也就是如果你没开启逃逸分析 , 那么就相当于关闭了这三种优化手段了 。
a.栈上分配(Stack Allocations)如果确定一个变量不会逃逸出方法外 , 那么C2会让这个对象直接在栈上分配内存创建实例 , 而不是在堆上 , 因为这样一来可以加快速度 , 二来是该变量占用的内存空间可以随着栈帧出栈而销毁 。
一般应用中 , 大多局部对象都可以使用栈上分配 , 这样垃圾收集器的压力就会小很多 。
b.同步消除(Synchronization Elimination)又名锁消除 , 多线程的情况下 , 有些变量会上同步锁 , 避免发生线程冲突问题 。 但是经过了逃逸分析后 , 该变量分析确定了它不会逃逸出线程 , 不会被其他线程访问到 , 那这个变量就没有必要上什么同步锁了 , 就可以清除掉这个变量的同步锁以节约资源 。
比较常用的例子是StringBuffer的append()方法 , 由于加了修饰符synchronized , 所以是线程安全的 , 但是如果你是单线程环境 , 就完全没有必要上这个锁了 。 所以开启了逃逸分析和锁消除的情况下(还要是C2才行) , 优化时就会将同步锁清除 , 大大的提升效率 。
参数:
-XX:+EliminateLocks 开启锁消除(jdk1.8 默认开启)-XX:-EliminateLocks 关闭锁消除

c.标量替换(Scalar Replacement)标量(Scalar)是指一个数据已经无法再分解成更小的数据来表示了 , Java中的原始数据类型(int、long等数值类型以及reference类型等)不能在进一步分解 , 这些就可以称为标量 。


聚合量:
相对的 , 如果一个数据可以继续分解 , 那它就称作聚合量(Aggregate) , Java中的Object对象就是最典型的聚合量 。
如果把一个Java对象拆散 , 根据程序访问的情况 , 将其使用到的成员变量恢复原始类型来访问就叫做标量替换 。
如果逃逸分析证明一个对象不会被外部访问的话 , 在优化时就可能进行标量替换 。 也就是在程序执行时 , 将不会创建整个对象 , 而是拆分为只创建它使用到的几个成员变量的标量 。 将对象拆分后 , 还可能结合栈上分配 , 将这些基本标量直接在栈上创建实例 , 可以为后续进一步的优化手段创建条件 。
这里用java语言举个例子 , 当然实际情况jvm是直接读取class文件的: