问题1:HotSpot是什么东东?
JVM制定了一个规范,不同的公司或者个人可以根据规范实现自己的Java虚拟机。为了便于理解可以将规范理解为接口,接口可以简化理解为一个方法,定义应该具有哪些功能。
例如swap(a,b) 意思就是交换a和b的值。至于方法的实现不关心,最终能把a,b值交换过来就成,这就是规范。不管黑猫还是白猫,能逮着老鼠就行。
HotSpot就是JVM规范的一个实现,也是最流行的一个虚拟机实现。除了HotSpot还有JRockit、J9 VM等。
问题2:Stop the world
先回忆下判断对象是否可以回收有哪些方法。
答案:引用计数和可达性分析,因为引用计数在对象之间存在相互引用关系的情况下无效,所以大部分的JVM实现都是采用可达性分析算法。
使用可达性分析算法,就需要枚举根节点,然后遍历对象,找到根节点到达不了的对象,也就是可回收的对象。
这里面就有一个问题,在JVM通过根节点遍历对象的时候,允许其他Java线程运行吗?
当然不能,因为可达性有可能会在线程运行过程中发生变化。例如,一个可通过根节点到达的对象,在线程继续运行但还没有开始回收这段时间,变为了不可达,当执行垃圾回收时是应该被回收掉的,但却没有。
所以这就导致GC运行时,必须停顿所有的Java执行线程,也就是Stop the world。
问题3:安全点
我们知道当执行GC时,就需要Stop the world。那什么时候执行GC呢?每运行一条指令就执行一次GC吗?想想也不合情理,就像每走一步就停下来,打打身上的灰尘一样,一公里的路得停多少次,一步距离能集多大点灰尘。合理的做法是先走到一个地点,这个地点呢还很干净,不会让你身上新增灰尘,然后再开始抖灰尘也就是垃圾回收。
这个点就是我们说的安全点,安全点的选取不能过大也不能过小,过大会导致垃圾太多,过小会导致收集太频繁,增加运行时负荷。
这里还有个问题,GC “Stop the world” 的时候怎么保证所有的线程都到了安全点?
方案1:强先式中断,GC中断时把所有线程都中断,如果发现有线程中断的地方不在安全点上,就恢复它,让它执行到安全点。
// 当下没有哪个虚拟机实现使用这个方案。。。
方案2:主动式中断,GC中断的时候设置一个标志位,各个线程执行的时候,主动轮询这个标志位(轮询标志的地方和安全点重合),发现为真时,就自己中断挂起。
问题4:安全区域
安全区域可以简单的理解为安全点的扩展,也就是在这个区域,引用关系不会发生变化,可以放心的执行GC。
那问什么要引入安全区这个概念呢?
我们知道,在线程sleep或者block的时候,是没法响应虚拟机的中断请求的,可以理解为没法设置执行线程的标志位,导致当线程获取CPU执行时间并轮询时,标志位并没有改变。
当线程进入安全区时,就标记一下,说明自己进入安全区了,这个时候JVM如果要GC是安全的;
当线程离开安全区时,要先检查系统是否已经完成了根节点枚举或者整个GC过程,如果完成了,就可以离开安全区,否则就需要等待。
今天就到这儿,明天继续^_^。