[JVM]-[深入理解Java虚拟机学习笔记]-逃逸分析

前言

逃逸分析的基本原理是:分析对象动态作用域,当一个对象在方法里面被定义后,他可能被外部方法所引用,例如作为调用参数传递到其它方法中,这种称为 方法逃逸;甚至还有可能被外部线程访问到,例如赋值给可以在其他线程中访问到的实例变量,这种称为 线程逃逸。对象由低到高的逃逸程度,可以分为 不逃逸方法逃逸 以及 线程逃逸
如果能证明一个对象不会逃逸到方法或线程之外,也即其它方法或线程无法访问到这个对象;或者逃逸程度比较低,则可以为这个对象采取不同程度的优化

栈上分配 (Stack Allocation)

栈上分配指的是,如果确定一个对象不会逃逸出线程之外,那就让这个对象在栈上分配而不是堆上,这样对象所占用的内存空间就可以随着栈帧的出栈而销毁
使用栈上分配的话,那些不会逃逸或者只会发生方法逃逸 (栈上分配可以支持方法逃逸但不能支持线程逃逸,毕竟虚拟机栈是线程私有的) 的对象就能随着方法的结束而自动销毁,而不会去占用堆上的空间然后留给垃圾收集器去回收它们,这样垃圾收集器子系统的压力就能下降很多,而且也节约了堆上空间

标量替换 (Scalar Replacement)

若一个数据已经无法再分解成更小的数据来表示,例如虚拟机中的原始数据类型 (int,long等数值类型以及引用类型数据。引用类型数据与对象不同,引用类型数据保存的是对象的地址,这个地址数值自然不能被拆分;但对象不同,它其中存储了许多变量,是可以拆分的) 都不能再进一步分解了,那么这些数据就可以被称为 标量
相对地,如果一个数据可以继续分解,那它就被称为 聚合量 ( A g g r e g a t e Aggregate Aggregate),Java 中的对象就是典型的聚合量
把一个 Java 对象拆散,根据程序访问的情况将其用到的成员变量恢复为原始类型来访问 ,这个过程就称之为 标量替换
如果逃逸分析能够证明一个对象不会被 方法 外部访问,并且这个对象可以被拆散,那么程序执行的时候就可以不去创建这个对象,而是改为直接创建它的若干个被这个方法使用到的成员变量
这样对象的成员变量就可以在栈上分配和读写。标量替换可以看成是栈上分配的一种特例,不仅将对象分配在栈上,而且是只分配其中会被方法用到的成员变量,但它对逃逸程度要求更高,不允许对象逃逸到方法外部,即只允许不逃逸的对象。可以理解为,在栈上分配的基础上,对象不仅不会逃逸出线程,还不会逃逸出方法,所以就为其进行更大程度的优化,不仅只在栈上分配他,而且将其拆分为标量的形式,减少了堆上创建对象的次数,减少了 GC 次数

同步消除 (Synchronization Elimination)

如果逃逸分析能够确定一个变量不会逃逸出线程,无法被其它线程访问,那么这个变量的读写就肯定不会有竞争,对这个变量实施的同步措施也就可以安全地消除掉。这样也就省掉了线程同步这个耗时的操作

猜你喜欢

转载自blog.csdn.net/Pacifica_/article/details/124480997