堆是分配对象存储的唯一选择么?
作者:互联网
如果经过逃逸分析后发现,一个对象并没有逃逸出方法的话,那么就可能被优化成栈上分配。这样就无需在堆上分配内存,也无需进行垃圾回收了,这也是最常见的堆外存储技术。
逃逸分析概述
1:这是一种可以有效减少Java程序中同步负载和内存堆分配压力的跨函数全局数据流分析算法
2:通过逃逸分析,Java HotSpot编译器能够分析出一个新的对象的引用的使用范围从而决定是否要将这个对象分配到堆上
3:逃逸分析的基本行为就是分析对象动态作用域:
当一个对象在方法中被定义后,对象只在方法内部使用,则认为没有发生逃逸
当一个对象在方法中被定义后,它被外部方法所引用,则认为发生逃逸,例如作为调用参数传递到其他地方
参数设置:
在JDK 6u23版本之后,HotSpot中默认就已经开启了逃逸分析
如果使用的是较早的版本,开发人员则可以通过:
选项“-XX:+DoEscapeAnalysis"显式开启逃逸分析
通过选项”-XX:+PrintEscapeAnalysis"查看逃逸分析的筛选结果
如何快速的判断是否发生了逃逸分析
就看new出来的对象实体是否有可能在方法外被调用
使用逃逸分析,编译器可以对代码做如下优化
一、栈上分配
将堆分配转化为栈分配,如果一个对象在子程序中被分配,要使指向该对象的指针永远不会逃逸,对象可能是栈分配的候选,而不是堆分配
JIT编译器在编译期间根据逃逸分析的结果,发现如果一个对象并没有逃逸出方法的话,就可能被优化成栈上分配。分配完成之后,继续在调用栈内执行,最后线程结束,栈空间被回收,局部变量对象也被回收。这样就无需进行垃圾回收
二、同步省略
如果一个对象被发现只能从一个线程被访问到,那么对于这个对象的操作可以不考虑同步
在动态编译同步块的时候,JIT编译器可以借助逃逸分析来判断同步块所使用的锁对象是否只能够被一个线程访问而没有被发布到其他线程。如果没有,那么JIT编译器在编译这个同步块的时候就会取消对这部分代码的同步。这样能大大提高并发性和性能。这个取消同步的过程就叫同步省略,也叫锁消除。
三、分离对象或标量替换
有的对象可能不需要作为一个连续的内存结构也可以被访问到,那么对象的部分(或全部)可以不存储在内存,而是存储在CPU寄存器中
标量是指一个无法再分解成更小的数据的数据,Java中的原始数据类型就是标量,相对的,哪些还可以分解的数据叫做聚合量,Java中的对象就是聚合量,因为它可以分解成其他聚合量和标量,在JIT阶段,如果经过逃逸分析,发现一个对象不会被外界访问的话,那么经过JIT优化,就会把这个对象拆解成为若干个其中包含的若干个成员变量来代替,这个过程就是标量替换。
标量替换参数设置:
参数-XX:+EliminateAllocations:开启标量替换(默认打开),允许将对象打散分配在栈上
注意:在Server模式下,才可以启用逃逸分析
对象实例都是分配在堆上
标签:分析,存储,同步,对象,唯一,逃逸,标量,分配 来源: https://blog.csdn.net/qq_43494013/article/details/121160957