前面的blog在理论上介绍了对象存活判定算法和垃圾收集算法,然而在HotSpot虚拟机上实现这些算法时必须对算法的执行效率有足够严格的考量,才能保证虚拟机高效运行。
1.可达性分析算法中的枚举根节点
在对象存活算法的可达性分析算法中从GC Roots节点找引用链这个操作为例。其中可达性分析对执行时间的敏感点的一个体现就是GC停顿上面,因为这项分析工作必须在一个能确保一致性的快照中进行–这里的一致性是指在整个分析期间整个执行系统看起来就像被冻结在某个时间点上,不可以出现分析过程中对象引用关系还在不断变化的情况,该点不满足就无法得到保证。这一点是导致GC进行时必须停顿所有Java执行线程(sun称为 “Stop the world”)的其中一个重要原因。
2.安全点
在HotSpot虚拟机中,借助于OopMap的协助下,可以快速且准确的完成GCRoots的枚举。但是不可能为每条指令都生成OopMap,这样空间成本就非常高。所以HotSpot中只是在“特定的位置”记录了这些信息,这些位置称为安全点,即程序执行时并非在所有地方都停顿下来开始GC,只有到达安全点时才能暂停。
safepoint的选择不能太少,不然GC等待时间会过长,也不能过于频繁以导致过大增大运行时的负荷。
对于safepoint 另一个需要考虑的问题是如何在GC时让所有线程(这里不包括执行JNI调用的线程)都跑到最近的安全点再停顿下来。有两种方案:
1. 抢先式中断:不需要线程的执行代码主动配合,在GC发生时,首先把所有线程中断,如果发现线程中断的地方不在安全点上就恢复线程,让它跑到安全点上。(这种几乎没人用了)
2. 主动式中断:当GC需要中断线程时,不直接对线程进行操作,仅仅简单的设置一个标志,各个线程执行时主动去轮询这个标志,发现中断标志为真就自己中断挂起。在这里轮询中断标志位与安全点重合的,另外再加上创建对象需要分配内存的地方。
3.安全域
前面的safepoint近乎完美的解决了如何进入GC的问题,但是实际情况还有一种没考虑到。safepoint机制保证了程序执行时,在不太长时间内就会遇到safepoint可进入GC。但是当线程处于sleep或则阻塞状态呢?这是线程无法响应JVM的中断请求了。
这种情况就需要安全区域(safe Region)来解决了。
安全区域:指在一段代码段中,引用关系不会发生变化,在这片代码段中任意地方开始GC都是安全的。
。