前往小程序,Get更优阅读体验!
立即前往
首页
学习
活动
专区
工具
TVP
发布
社区首页 >专栏 >JVM内存逃逸与栈上分配,程序员必须掌握的知识

JVM内存逃逸与栈上分配,程序员必须掌握的知识

作者头像
黎明大大
发布2020-09-08 16:27:03
1.6K0
发布2020-09-08 16:27:03
举报
逃逸分析
内存逃逸主要是对象的动态作用域的改变而引起的,故而内存逃逸的分析就是分析对象的动态作用域。
发生逃逸行为的情况分为两种:方法逃逸和线程逃逸
方法逃逸
当方法创建了一个对象之后,这个对象被外部方法所调用,这个时候方法运行结束要进行GC时,本该方法的对象被回收,却发现该对象还存活着,没法回收,则称为 "方法逃逸"
简单来说:就是当前方法创建的对象,本该是当前方法的栈帧所管理,却被调用方所使用,可以称之为内存逃逸

下图中,可以看到直接将User对象返回出去,这样这个User对象有可能会被其他地方所改变,这样他的作用域就不只是在方法内部了,这样就是逃逸到方法外部了

那怎么样才能够不让方法逃逸呢?很简单,就不返回User对象即可,看下图

线程逃逸
上面的例子,直接将对象进行返回出去,该对象很有可能被外部线程所访问,如:赋值给变量等等 则称为 "线程逃逸
栈上分配

如果能够证明一个对象,不会进行逃逸到方法或线程外的话,则可以对该变量进行优化

当我们创建一个对象的时候,会立马想到该对象是会存储到堆空间中的,而垃圾回收机制会在堆空间中回收不再使用的对象,但是筛选可回收对象,还有整理对象都需要消耗时间,如果能够通过逃逸分析确定某些对象不会逃出到方法外的话,那么就可以直接让这个对象在栈空间分配内存,这样该对象会随着方法的执行完毕自动进行销毁

简单来说:比如说,我上一篇文章有写到,一个方法对应一个栈帧,而我的对象是在当前的栈帧中所管理的,并非逃逸到方法外,所以创建的对象是在栈中,而非堆中,所以称为 "栈上分配"
同步消除
线程同步本身比较耗时,若确定了一个变量不会逃逸出线程,无法被其他线程访问到,那这个变量的读写就不会存在竞争,则可以消除对该对象的同步锁
标量替换
1、标量是指不可分割的量,如java中基本数据类型和reference类型,都不能再进一步分解,他们就可以称为标量。
2、若一个数据可以继续分解,那就称之为聚合量,而对象就是典型的聚合量。
3、若逃逸分析证明一个对象不会逃逸出方法,不会被外部访问,并且这个对象是可以被分解的,那程序在真正执行的时候可能不创建这个对象,而是直接创建这个对象分解后的标量来代替。这样就无需在对对象分配空间了,只在栈上为分解出的变量分配内存即可。

注意:

逃逸分析是比较耗时的,所以性能未必提升很多,因为其耗时性,采用的算法都是不那么准确但是时间压力相对较小的算法来完成的,这就可能导致效果不稳定,要慎用。 由于HotSpot虚拟机目前的实现方法导致栈上分配实现起来比较复杂,所以HotSpot虚拟机中暂时还没有这项优化。

相关JVM参数

-XX:+DoEscapeAnalysis 开启逃逸分析、 -XX:+PrintEscapeAnalysis 开启逃逸分析后,可通过此参数查看分析结果。 -XX:+EliminateAllocations 开启标量替换 -XX:+EliminateLocks 开启同步消除 -XX:+PrintEliminateAllocations 开启标量替换后,查看标量替换情况。

本文参与 腾讯云自媒体分享计划,分享自作者个人站点/博客。
如有侵权请联系 cloudcommunity@tencent.com 删除

本文分享自 作者个人站点/博客 前往查看

如有侵权,请联系 cloudcommunity@tencent.com 删除。

本文参与 腾讯云自媒体分享计划  ,欢迎热爱写作的你一起参与!

评论
登录后参与评论
0 条评论
热度
最新
推荐阅读
目录
  • 逃逸分析
    • 方法逃逸
      • 线程逃逸
        • 栈上分配
          • 同步消除
            • 标量替换
            领券
            问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档