栈分配、逃逸分析与TLAB -JVM( 二 )


逃逸类别
经过逃逸分析之后 , 可以得到三种对象的逃逸状态 。
1、(全局逃逸) ,  即一个对象的引用逃出了方法或者线程 。例如 , 一个对象的引用是复制给了一个类变量 , 或者存储在在一个已经逃逸的对象当中 , 或者这个对象的引用作为方法的返回值返回给了调用方法 。
2、(参数级逃逸) , 即在方法调用过程当中传递对象的应用给一个方法 。这种状态可以通过分析被调方法的二进制代码确定 。
3、(没有逃逸) , 一个可以进行标量替换的对象 。可以不将这种对象分配在传统的堆上 。
另一种解释 , 其实都一样:
1、方法逃逸:在一个方法体内 , 定义一个局部变量 , 而它可能被外部方法引用 , 比如作为调用参数传递给方法 , 或作为对象直接返回 。或者 , 可以理解成对象跳出了方法 。
2、线程逃逸:这个对象被其他线程访问到 , 比如赋值给了实例变量 , 并被其他线程访问到了 。对象逃出了当前线程 。
再提一下“堆”
堆、栈是真实的内存物理区

栈分配、逃逸分析与TLAB -JVM

文章插图
java堆:是虚拟机中所管理的内存中区域最大的一块 , 是被所有线程共享的一块内存区域 , 在虚拟机启动时创建 。此内存区域的唯一目的就是存放对象实例 , 几乎所有的对象实例都在这里分配内存 。java堆是垃圾收集器管(GC)理的主要区域 。
逃逸分析作用
逃逸分析 , 是一种可以有效减少Java 程序中同步负载和内存堆分配压力的跨函数全局数据流分析算法 。通过逃逸分析 , Java 编译器能够分析出一个新的对象的引用的使用范围从而决定是否要将这个对象分配到堆上 。逃逸分析( ) 。
逃逸分析的好处
如果一个对象不会在方法体内 , 或线程内发生逃逸(或者说是通过逃逸分析后 , 使其未能发生逃逸)
1. 栈上分配
一般情况下 , 不会逃逸的对象所占空间比较大 , 如果能使用栈上的空间 , 那么大量的对象将随方法的结束而销毁 , 减轻了GC压力
2. 同步消除
如果你定义的类的方法上有同步锁 , 但在运行时 , 却只有一个线程在访问 , 此时逃逸分析后的机器码 , 会去掉同步锁运行 。
3. 标量替换
Java虚拟机中的原始数据类型(int , long等数值类型以及类型等)都不能再进一步分解 , 它们可以称为标量 。相对的 , 如果一个数据可以继续分解 , 那它称为聚合量 , Java中最典型的聚合量是对象 。如果逃逸分析证明一个对象不会被外部访问 , 并且这个对象是可分解的 , 那程序真正执行的时候将可能不创建这个对象 , 而改为直接创建它的若干个被这个方法使用到的成员变量来代替 。拆散后的变量便可以被单独分析与优化 , 可以各自分别在栈帧或寄存器上分配空间 , 原本的对象就无需整体分配空间了 。
抄录:
同步消除:
在动态编译同步块的时候 , JIT编译器可以借助逃逸分析来判断同步块所使用的锁对象是否只能够被一个线程访问而没有被发布到其他线程 。
如果同步块所使用的锁对象通过这种分析被证实只能够被一个线程访问 , 那么JIT编译器在编译这个同步块的时候就会取消对这部分代码的同步 。这个取消同步的过程就叫同步省略 , 也叫锁消除 。