本文主要是介绍HotSpot虚拟机OopMap、SafePoint、RememberedSet,希望对大家解决编程问题提供一定的参考价值,需要的开发者们随着小编来一起学习吧!
HotSpot虚拟机垃圾回收算法细节
- 快速根节点枚举OopMap
- 安全点Safepoint和OopMap
- 解决对象跨代引用Remembered Set
- 如何支持并发标记
快速根节点枚举OopMap
- GC Roots的节点主要在全局性的引用(例如常量或类静态属性)与执行上下文(例如 栈帧中的本地变量表)中
- 目前主流Java虚拟机使用的都是准确式垃圾收集,准确式就是说给定某个位置上的某块数据,要能知道它的准确类型是什么,这样才可以合理地解读数据的含义;GC所关心的含义就是“这块数据是不是指向GC堆的引用”。
要实现这样的GC,JVM就要能够判断出所有位置上的数据是不是指向GC堆里的引用,包括活动记录(栈+寄存器)里的数据。 - 一个不漏地从方法区等GCRoots开始查找的话可以支持准确式GC,但是查找效率太慢。所以HotSpot从外部记录下类型信息,存成映射表来支持上述的准确式GC,这就是OopMap。
- 要实现这种功能,需要虚拟机里的解释器和JIT编译器都有相应的支持
- 每次都遍历原始的映射表,循环的一个个偏移量扫描过去,一旦类加载动作完成的时候, HotSpot就会把对象内什么偏移量上是什么类型的数据计算出来(解释器)
- 为每个映射表生成一块定制的扫描代码(想像扫描映射表的循环被展开的样子),以后每次要用映射表就直接执行生成的扫描代码,就会在特定的位置记录下栈里和寄存器里哪些位置是引用(JIT编译器)
- 在HotSpot中,对象在堆内存中的存储布局可以划分为三个部分:对象头(Header)、实例数据(Instance Data)和对齐填充(Padding)。对象的实例数据里有记录自己的OopMap,记录了在该类型的对象内什么偏移量上是什么类型的数据。所以从对象开始向外的扫描可以是准确的;这些数据是在类加载过程中计算得到的。
安全点Safepoint和OopMap
- 每个被JIT编译过后的方法会在一些特定的位置记录下OopMap,记录了执行到该方法的某条指令的时候,栈上和寄存器里哪些位置是引用。这样GC在扫描栈的时候就会查询这些OopMap就知道哪里是引用了。
- 这些特定的位置主要在:
- 循环的末尾
- 方法临返回前 / 调用方法的call指令后
- 可能抛异常的位置
这种位置被称为“安全点”(safepoint),所以,每个方法可能会有好几个oopMap,就是根据safepoint把一个方法的代码分成几段,每一段代码一个oopMap,作用域自然也仅限于这一段代码;
- 所以HotSpot中GC不是在任意位置都可以进入,而只能在safepoint处进入;
- 可以把oopMap简单理解成是调试信息。在源代码里面每个变量都是有类型的,但是编译之后的代码就只有变量在栈上的位置了。oopMap就是一个附加的信息,告诉你栈上哪个位置是什么类型的数据。
解决对象跨代引用Remembered Set
- 在HotSpot虚拟机中,基于分代收集理论的垃圾收集器,使用记忆集(Remembered Set)解决对象跨代引用带来的问题;
- 记忆集是一种用于记录从非收集区域指向收集区域的指针集合的抽象数据结构。
- 常用数据结构形式为卡表(一个字节数组)
CARD_TABLE [this address >> 9] = 0;
字节数组CARD_TABLE的每一个元素都对应着其标识的内存区域中一块特定大小的内存块,这个 内存块被称作“卡页”(Card Page)。HotSpot中使用的卡页是2的9次幂,即512字节(地址右移9位,相当于用地址除以512)。
4. 卡表之所以使用byte数组而不是bit数组主要是速度上的考量,现代计算机硬件都是最小按字节寻址的, 没有直接存储一个bit的指令,所以要用bit的话就不得不多消耗几条指令。
5. HotSpot虚拟机里是通过写屏障(Write Barrier)技术维护卡表状态的。写屏障可以看作在虚拟机层面对“引用类型字段赋值”这个动作的AOP切 面,在引用对象赋值时会产生一个环形(Around)通知,供程序执行额外的动作,也就是说赋值的 前后都在写屏障的覆盖范畴内。
6. 应用写屏障后,虚拟机就会为所有赋值操作生成相应的指令,一旦收集器在写屏障中增加了更新 卡表操作,无论更新的是不是老年代对新生代对象的引用,每次只要对引用进行更新,就会产生额外 的开销,不过这个开销与Minor GC时扫描整个老年代的代价相比还是低得多的。
如何支持并发标记
- 三色标记法辅助推导:
- 白色:代表不可达或者没有扫描过,扫描完仍是白色的对象就会被清除回收;
- 黑色:代表已扫描且是安全存活
- 灰色:代表已扫描但这个对象上至少存在一个引用还没有被扫描过;
- 初始状态:GCRoot对象是黑色,其他对象都是白色
- 重要原则:黑色对象不可能直接(不经过灰色对象)指向某个白色对象
- CMS(Concurrent Mark Sweep)使用增量更新算法来保证重新标记阶段,可以修正并发标记期间因用户程序继续运作而导致标记产生变动的那一部分对象的标记记录。增量更新使用三色标记法可以理解为:当黑色对象插入新的指向白色对象的引用关系时,就将这个新 插入的引用记录下来,等并发扫描结束之后,再将这些记录过的引用关系中的黑色对象为根,重新扫 描一次。
- G1、Shenandoah使用原始快照来实现并发标记的。原始快照:当灰色对象要删除指向白色对象的引用关系时,就将这个要删 除的引用记录下来,在并发扫描结束之后,再将这些记录过的引用关系中的灰色对象为根,重新扫描 一次。这也可以简化理解为,无论引用关系删除与否,都会按照刚刚开始扫描那一刻的对象图快照来 进行搜索。
这篇关于HotSpot虚拟机OopMap、SafePoint、RememberedSet的文章就介绍到这儿,希望我们推荐的文章对编程师们有所帮助!