安全点与安全区域
hotspot中进行垃圾回收的根节点枚举这一步时必须要求暂停所有用户线程,设置了一些特定位置表示当程序运行到这一步时,可以暂停来进行垃圾回收。同时程序也是在安全点来记录OopMap。
HotSpot使用主动式抢断来中断线程,即在需要进行垃圾回收时设置一个标志位,程序运行时回查询这个标志,当标志位设置位真时就会运行到最近的安全点主动中断。查询标志位的时机除了所有安全点的位置还包括创建对象和其他需要在堆上分配内存的地方(检查是否要发生垃圾收集,避免内存不足)
查询标志位的具体操作为:使用test指令查询一块内存区域,需要设置安全点时会把这块区域设置为不可读,出现异常后就可以由预先注册的异常处理器来挂起等待。
安全区域:程序在进入sleep等不运行的状态时,会标识自身进入安全区域。进行垃圾回收时就不用除了以声明处于安全区域的线程,离开安全区域时回查询用户线程的暂停是否结束,未结束则等待。
记忆集
存储一个区域内的跨代引用信息的数据结构,通常有以下几种精度:
- 字节精度:精确到一个字节,表示该字节包含跨代指针
- 对象精度:精确到一个对象,表示该对象内有跨代指针
- 卡精度:精确到一块内存区域,表示该区域内的对象包含跨代指针
其中按照卡精度的记忆集被称为卡表,HotSpot中的卡表为一个字节数组,记录卡表的简单逻辑如下
CARD_TABLE[ (目标的内存地址) -- > 9 ] = 0;
卡表的每一个元素对应的内存区域被称作卡页,存在跨代指针时会被标识为 1。
读屏障与写屏障
读屏障与写屏障的在功能上与aop类似,HotSpot使用写屏障在维护卡表,某些垃圾收集器会使用读屏障来保证垃圾收集时移动对象的正确性。
可达性分析时并发的枚举节点
可达性分析中枚举根节点时必须暂停所有用户线程,,但枚举所有节点的过程可以和用户线程一起并发执行,简单逻辑如下:
根据对象是否被方位将对象标记位三种颜色:
- 白色:未被垃圾收集起访问过的节点
- 灰色:已被垃圾收集器访问,但其还存在引用未被扫描
- 黑色:已被垃圾收集器访问,且所有引用都被扫描过
不进行同步时存在的问题:如果同时满足以下两个条件,会使得被引用的对象被标记为死亡:
- 产生了一条或多条从黑色到白色对象的引用
- 删除了全部从灰色对象到某一个白色对象的直接或间接引用
解决方案就是破坏其中一种条件:
- 在黑色对象插入新的指向白色对象的指针时,记录下黑色对象,在扫描结束后重新扫描一次,这种方法叫做增量更新
- 在灰色对象删除对白色对象的引用时把删除的引用记录下来,扫描结束后以这些灰色对象为根按原有的引用关系扫描一遍,这种方法叫做原始快照