Java的Escape Analysis和锁优化

Java 程序运行时,JVM 会将.class字节码文件解释成机器能够识别的指令,逐条解释再执行的过程导致执行速度比可执行的二进制文件慢很多。为了解决这种问题出现了JIT(即时编译)技术。JIT 主要有两个功能:

  • 缓存Hot Spot Code(热点代码:频繁运行的方法或代码块)对应的本地机器相关的机器码,方便下次调用。
  • 代码编译优化。

而在 JIT 的代码优化过程中,最重要的就是逃逸分析(Escape Analysis)。

对象逃逸状态

  • GlobalEscape(全局逃逸): 一个对象的作用范围逃出了当前方法或当前线程,有以下3个场景:
    • 对象的引用赋值给类变量或者静态变量
    • 对象作为当前方法的返回值
    • 对象存储在一个已经发生逃逸的对象中 或 它已经是一个发生逃逸的对象
  • ArgEscape(参数逃逸): 一个对象被作为方法参数传递或者被参数引用,但在调用期间没有发生全局逃逸
  • NoEscape(没有逃逸): 对象的作用范围在一个方法体

对象动态作用域

  • 方法逃逸:对象在方法中被定义,但却被方法以外的其他代码使用。如传参到其他方法中。
  • 线程逃逸:一个对象由某个线程在方法中被定义,但却被其他线程访问。如类变量、公用的或有 get、set 方法的实例变量等

利用逃逸分析,编译器可以对代码做如下优化:

  • 同步省略:在动态编译同步块的时候,JIT编译器可以借助逃逸分析来判断同步块所使用的锁对象是否只能够被一个线程访问而没有发布到其他线程,如果是的话,那么针对这个对象的同步措施就可以省略掉,即同步省略,也叫锁销除。例如 Vector 和 StringBuffer 这样的类,它们中的很多方法都是有锁的,当某个对象确定是线程安全的情况下,JIT编译器会在编译这段代码时进行锁销除来提升效率。
// 在使用synchronized的时候,如果JIT经过逃逸分析之后发现并无线程安全问题的话,就会做锁消除。
public void f() {
    Object hollis = new Object();
    synchronized(hollis) {
        System.out.println(hollis);
    }
}
// 代码中对hollis这个对象进行加锁,但是hollis对象的生命周期只在f()方法中,并不会被其他线程所访问到,所以在JIT编译阶段就会被优化掉。优化成:
public void f() {
    Object hollis = new Object();
    System.out.println(hollis);
}
  • 标量替换:标量(Scalar)是指无法再分解成更小粒度的数据,例如 Java 中的原始数据类型(int,long等)和对象的引用;相对如果一个数据可以继续分解,则称之为聚合量(Aggregate),例如 Java对象。在 JIT 编译过程中,经过逃逸分析确定一个对象不会被其他线程或者方法访问,那么会将对象的创建替换成为多个成员变量的创建,即标量替换。标量替换减少了创建对象需要的堆内存,同时也不用进行 GC。
  • 栈上分配:指对象和数据不是创建在堆上,而是创建在栈上,随着方法的结束自动销毁。但实际上,JVM 例如常用的HotSpot虚拟机并没有实现栈上分配,实际是用标量替换代替实现的,即当对象没有发生逃逸时,该对象就通过标量替换分解成成员标量分配在栈内存中,和方法的生命周期一致,随着栈帧出栈时销毁。

锁优化

  • 锁消除:锁消除的主要判定依据来源于逃逸分析的数据支持
  • 锁粗化:编写代码的时候,推荐将同步块的作用范围限制得尽量小。但如果在一系列的连续操作都对同一个对象反复加锁和解锁,甚至加锁操作出现在循环体中,那即便没有线程竞争,频繁地进行互斥同步操作也会导致不必要的性能损耗。锁粗化虽然从技术上讲不属于逃逸分析子系统中的一部分,但也是通过分析作用域来提高内部锁的性能。如果JVM探测到有一串零碎的操作都对同一个对象加锁,将会把加锁同步的范围扩展到整个操作序列的外部(JVM尝试往前查找同一个对象的解锁操作。如果能匹配上,会考虑将两个锁区域合并,并删除一组加解锁操作)。当连续获取同一个对象的锁时,JVM会检查多个锁区域是否能合并成一个更大的锁区域。

  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值