您的位置:首页 > 其它

《JVM学习系列》四.垃圾收集算法及HotSpot的算法实现

2016-11-02 19:03 344 查看

0 说明

本篇文章只是介绍几种算法的思想,实现细节不会过多的讨论。

1.垃圾收集算法

1.1标记-清除算法

算法分为标记和清除两个阶段:首先标记出所有需要回收的对象,在标记完成后统一回收所有被标记的对象,它的标记过程就是使用可达性算法进行标记的。

主要缺点有两个:

效率问题,标记和清除两个过程的效率都不高

空间问题,标记清除之后会产生大量不连续的内存碎片

1.2复制算法

复制算法:将可用内存按照容量分为大小相等的两块,每次只使用其中的一块。当这一块的内存用完了,就将还存活着的对象复制到另一块上面,然后把已使用过的内存空间一次清理掉。内存分配时不用考虑内存碎片问题,只要一动堆顶指针,按顺序分配内存即可,实现简单,运行高效。代价是将内存缩小为原来的一半。

1.3标记-整理算法

标记整理算法(Mark-Compact),标记过程仍然和“标记-清除”一样,但后续步骤不是直接对可回收对象进行清理,而是让所有存活对象向一端移动,然后直接清理掉端边界以外的内存。

1.4分代收集算法

根据对象存活周期的不同将内存分为几块。一般把Java堆分为新生代和老年代,根据各个年代的特点采用最合适的收集算法。在新生代中,每次垃圾收集时有大批对象死去,只有少量存活,可以选用复制算法。而老年代对象存活率高,使用标记清理或者标记整理算法。

2.HotSpot的算法实现

2.1枚举根节点

GC进行时必须停顿所有的Java执行线程,即使实在号称(几乎)不会发生停顿的CMS收集器中,美剧根节点时也是必须要停顿的。

在HotSpot的实现中,是使用一组称为OopMap的数据结构来达到找到引用对象的目的的。

2.2安全点

HOtSpot并没有为每一个指令都生成OopMap,只是在“特定的位置”记录了这些信息,这些位置就称为安全点,即程序只有在到达安全点时才能暂停下来开始GC。安全点的选定不能太少,虚拟机需要等待太长时间,也不能太多以至于过分增大运行时的负荷。

安全点的选定基本上是以程序“是否具有让程序长时间执行的特征”为标准选定的—-因为每条指令执行的时间都非常短暂,程序不太可能因为指令流长度太长这个原因而过长时间运行,“长时间执行”的最明显特征就是指令序列复用,例如方法调用、循环跳转、异常跳转等,所以具有这些功能的指令才会产生安全点。

由于GC时,需要所有线程在安全点中断,一种是抢占式中断;另一种是主动式中断,其中抢占式中断就是在GC发生时,首先把所有线程全部中断,如果发现有线程不在安全点,就恢复线程,让它跑到安全点上。现在几乎没有JVM采用这种方式来响应GC事件。 而主动式中断的思想不是直接对线程操作,仅仅是简单设置一个标志,各个线程执行时主动去轮询这个标志,发现中断标志为真时就自己中断挂起。轮询标志的地方和安全点是重合的。

2.3安全区域

有了安全点之后,也不能完美地解决GC的问题,但实际情况却不一定。当程序没有被分配cpu时间,典型的例子就是线程处于sleep或者blocked状态,这个时候线程无法响应JVM的中断请求,“走”到安全点挂起。对于这种情况,就需要安全区域来解决。

安全区域是指在一段代码片段之中,引用关系不会发生变化。在这个区域中的任意地方开始GC都是安全的,我们也可以把安全区域看做是被扩展的安全区域。

关于内存回收,如何进行是由JVM所采用的GC收集器决定的,而通常JVM中往往不止有一种GC收集器。关于GC收集器的部分略过,有兴趣的可以自己研究。
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: