携手创作,共同成长!这是我参与「掘金日新计划 · 8 月更文挑战」的第3天,点击查看活动详情
上文提到了安全点的概念,为的是减少生成OOPMap的内存开销,以及为中断线程为GC提供一个一致性快照提供合理的中断点
那么遗留下来的问题,当GC开始前,线程已经进入Sleep或Blocked状态呢?
在挂起状态的线程是无法轮询标志的,也就无法自动前往最近的安全点,如若是长时间的挂起状态直到GC结束后才开始执行还好,若GC中途线程结束挂起开始运行,这可如何是好?这种风险虚拟机可以但没必要承担的
所以就引入安全区域的概念
安全区域(Safe Region)
安全区域是指能够确保在某一段代码片段之中,引用关系不会发生变化,因此,在这个区域中任 意地方开始垃圾收集都是安全的。我们也可以把安全区域看作被扩展拉伸了的安全点。 --摘自《深入理解Java虚拟机》
当线程进入Sleep或Blocked状态时,它只是在等待,等待拿到锁或者结束睡眠,本身的状态不会再发生改变所以就类似于到达了一个安全点,在这个区域内任意一行代码,全都是安全点,这就是安全区域
代码示例:
public void test() {
Object o1 = new Object();
o1.setObj(new Object());
// Safe Region 的开始
System.out.println(123);
System.out.println(o1.getClass());
// Safe Region 的结束
// 在此之间对象引用关系并没有发生改变
}
在虚拟机执行线程的过程中,如果线程进入了安全区域,则会标识自身已进入,当GC发起时,收集器就不回去处理这些线程,当线程离开安全区域时,会检查jvm是否已经完成了根节点枚举或者已经过了需要暂停用户线程的阶段,如果是则继续执行,否就持续等待直到获得可以离开的信号
GC Roots枚举执行流程浅分析
(流程图绘画可能有点杂乱)