JVM——对象堆外分配(栈上分配)、变量逃逸

概述

堆空间是GC的重点区域,作为对象分配的主要区域,所以和程序性能有着十分密切的关系。由于GC的频率对JVM调优至关重要,特别是老年代的Major GC对STW的影响,新生代的Minor GC速度很快。所以能够想到的就是对象如果不在堆上分配,那么GC的频率就会降低,STW的时间就会减少。

随着JVM技术的发展,栈上分配、标量化替换技术等,使得之前所说的所有对象都在堆上分配变得不是那么绝对了。

变量逃逸

经过逃逸分析(Escape Analysis),如果一个对象并没有逃出方法的话,那么就有可能被优化为栈上分配(栈上分配是常见的堆外储存技术,Excelsior JET VM使用了,Hotspot还没有)。这样就不用在堆上分配内存,该对象也不会参与堆上分配策略的判断以及GC的过程。逃逸分析在JDK6 6u23版本之后就默认开启了,早前版本通过-XX:+DoEscapeAnalysis开启,通过-XX:+PrintEscapeAnalysis查看逃逸分析结果。

逃逸分析是一个有效减少Java程序中同步负载和内存堆分配压力的跨函数全局数据流分析算法:

  • 经过逃逸分析,VM编译器可以分析出一个对象的引用的使用范围,从而决定是否要将这个对象分配到堆上。
  • 逃逸分析的基本判断原则就是分析对象动态作用域:
    • 当一个对象在方法中定义后(局部变量),对象只在方法内部使用,则认为没有发生逃逸。
    • 当一个对象在方法中被定义后,他被外部方法所引用,则认为发生变量逃逸。

代码优化:

  • 所以在开发过程中能使用局部变量就不要使用成员变量,局部变量在方法对应的栈帧的局部变量表中储存,随着方法的执行结束就弹出栈,不存在垃圾回收的需要
  • 锁消除:逃逸分析,将会判断当前加锁对象是否是有一条线程访问,比如锁对象是局部变量创建的,那么每次执行该方法,都会创建一个新的锁对象,加锁就毫无意义,逃逸分析将会把该锁消除,提高执行效率
  • 标量替换:使用-XX:+EliminateAllocations参数开启关闭,默认开启
    • 标量:一个无法被分解成更小的数据,Java中的原始数据类型就是标量
    • 聚合量:还可以继续分解的数据对象,Java中的对象就是聚合量(有原始类型的成员变量,或者其他引用类型的成员变量)
    • 在JIT编译器编译阶段,经过逃逸分析,发现某些局部变量是聚合量,就会尝试将其“拆解”,此时就不会在堆中创建对象,而是直接由标量代替,存放在栈帧的局部变量表中,随着方法执行完毕而“消亡”
public void a() {
    //X x = new X();
    int m = 0;
    int n = 1;
}

class X {
    int m = 0;
    int n = 1;
}

 

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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值