安全点
JVM只有当程序运行到特定位置时才能暂停用户线程转入GC对应的流程,这个位置就是安全点。
1.为什么要有安全点?
我们针对于栈和方法区这种基本上固定为GC Roots的区域,因为我们区域空间很大,如果每次我们都线性遍历一遍区域找到所有的gc roots,这样太浪费我们的时间了,所以hotspot虚拟机就提供了一种OopMap的数据结构,在特定位置上记录下我们栈上哪些位置是引用,这样我们枚举GC roots的时候就不需要进行扫描,直接就能够得到对应的引用。这些位置就是安全点。
2.安全点一般设立在什么位置?
一些代表将会长时间进行执行的指令如方法调用、循环跳转、异常跳转等。这些指令代表着我们的代码将长时间不会继续往下执行,那么我们为了不让GC等待太久,就应该在这些地方设立安全点。
3.那么如何保证GC的时候所有线程都处于安全点呢?
抢先式中断:在需要进行GC时,程序首先会中断所有的用户线程,然后判断用户线程是否停在了安全点上,如果没有则让对应的线程恢复执行,等待执行到了安全点上再进行等待。(这种方法现在已经没有虚拟机使用)
主动式中断:在需要进行GC时,程序会设置一个标志位,表示马上需要执行垃圾回收了,对应的用户线程在执行时,会不断地轮询这个标志位,如果中断标志位为真,那么程序会在执行到下一个安全点时自动中断挂起。
4.安全区域
对于一些在休眠或者阻塞的线程,我们不可能让他们继续执行到下一个安全点,那么hotspot就引入了安全区域的概念。
针对于像线程阻塞啊休眠啊这些状态,hotspot虚拟机将其视为处于安全区域内,在安全区域内对应的引用关系不会发生改变,因此在这个区域任意位置进行垃圾收集都是安全的。
当用户线程进入安全区域后,用户线程会标识自己已经进入了安全区域,那么jvm在进行垃圾收集时就不会考虑这些已经进入安全区域的线程,当用户线程即将离开安全区域时,会查询jvm是否即将进行垃圾回收,如果不需要那么用户线程就继续执行,否则它将会等待垃圾回收完成。