首页 > java > HotSpot GC可达性分析的实现原理

HotSpot GC可达性分析的实现原理

作者:bin

一、基本概念

基本思想就是通过一系列的称为 “GC Roots” 的对象作为起点,从这些节点开始向下搜索,节点所走过的路径称为引用链,当一个对象到 GC Roots 没有任何引用链相连的话,则证明此对象是不可用的。

可作为 GC Roots 的对象包括下面几种:
虚拟机栈(栈帧中的本地变量表)中引用的对象
本地方法栈(Native 方法)中引用的对象
方法区中类静态属性引用的对象
方法区中常量引用的对象

二、GC roots是如何快速统计的

栈中的引用是动态的,每次GC都对全栈进行扫描太费时间类,所以在hotspot中,使用一个叫OopMap的数据结构,来记录,OopMap可以理解为一个标签,他记录来当前节点的调试信息。

在OopMap帮助下,可以快速的找到GC roots,但是我们不能随时都去维护OopMap,那样就和扫全栈一样低效,HotSpot中是在一个叫安全点的地方去维护

三、安全点

方法返回,异常返回,循环跳转这些位置被叫做安全点

用户线程到了安全点后就会挂起,让GC线程去做回收,HotSpot中采用的是主动式中断:
用户线程跑到安全点时,会判断一个全局的中断标识是否为真, 如果为真,即挂起当前线程

四、安全区域

用户线程blocked、sleep时称为进入安全区域
这时引用关系不会发生变化,在这个区域进行垃圾回收时安全的。
但是,当线程离开安全区域前,会判断垃圾回收是否完成,如果未完成,就要等回收完成再离开安全区域。

五、记忆集和卡表

用于解决跨代收集的问题,避免吧整个老年代放入GC root的扫描的范围,记忆集的精度可以是字节、对象、卡,HotSpot中,使用的是卡表,
卡表记的是「非垃圾收集区域」 =》 「垃圾收集区域的」映射,用的是字节数组,一个字节对应这个内存区域,当字节标识为1时,表示存在跨代引用即为「脏页」,那么当前卡页就需要加入GC root扫描。
例如年轻代回收时,就要将有老年代引用年轻代元素的内存页(page),加入GCRoot中扫描,就是card=1的那些页就行。

六、写屏障

记忆集是通过写屏障来维护的,写屏障是在引用赋值的前后做一个around的增强,HotSpot中大部分都是做的后写屏障,只有G1做了前写屏障。

void oop_field_store(oop* field, oop new_value) { // 引用字段赋值操作
*field = new_value;
// 写后屏障,在这里完成卡表状态更新 post_write_barrier(field, new_value);
}

伪共享问题,一个卡表元素占1个字节,64个卡表刚好占一个缓存行,对应卡页为32kb的内存空间,如果正好有多个线程去更新这32kb的空间,那么就会同时去更新卡表,就会有性能问题,HotSpot虚拟机中可以通过-XX:+UseCondCardMark来开启判断,如果卡表已经为脏页,就不去更新了,但是多了一次比较的过程,性能损耗根据应用实际情况来看了。

您必须 [ 登录 ] 才能发表留言!