G1和CMS区别
CMS
CMS是基于并发的 "标记-清理" 算法实现的老年代收集器,以获取最短回收停顿时间为目标。
CMS回收垃圾的4个阶段
-
初始标记(Stop The World):独占CPU,仅标记GC-Roots能直接关联的对象;
-
并发标记:可以和用户线程并行执行,标记所有可达对象;
-
重新标记(Stop The World):独占CPU,对并发标记阶段用户线程运行产生的垃圾对象进行标记修正;
-
并发清理:可以和用户线程并行执行,清理垃圾。
CMS优缺点
优点
- 并发收集,低停顿。
缺点
- 内存空间碎片:“标记-清理”算法会产生大量的空间碎片,会出现老年代空间很大但无法找到连续空间来分配当前对象,提前触发一次FullGC;
- 对CPU敏感:在并发阶段虽然不会导致用户线程停顿,但是会因为占用了一部分线程使应用程序变慢,适用于老年代并不频繁GC的场景;
- 无法处理浮动垃圾:在最后一步并发清理的过程中,用户线程执行也会产生垃圾,但是这部分垃圾是在标记之后,所以只有等到下一次GC的时候清理掉,这部分垃圾叫浮动垃圾。
G1
JDK9以后的默认GC,基于"标记-整理"算法,将内存进行Region分区,不区分新生代老生代,除了追求低停顿外,还能建立可预测的停顿时间 。
G1回收垃圾的4个阶段
-
初始标记(Stop the World):标记GC Roots 可以直接关联的对象,该阶段需要CPU独占 ,但是耗时短;
-
并发标记:从GC Roots开始堆中对象进行可达性分析,寻找存活的对象,可以与其他程序并发执行,耗时较长;
-
最终标记(Stop the World):并发标记期间用户程序会导致标记记录产生变动(好比一个阿姨一边清理垃圾,另一个人一边扔垃圾)虚拟机会将这段时间的变化记录在Remembered Set Logs 中。最终标记阶段会向Remembered Set合并并发标记阶段的变化。这个阶段需要 Stop the World ,也可以并发执行;
-
筛选回收(Stop the World):对每个Region的回收成本进行排序,根据用户所期望的GC停顿时间来制定回收计划。Sun公司透露这个阶段其实也可以做到并发,但考虑到停顿线程将大幅度提高收集效率,所以选择停顿。
G1优缺点
优点
- 可以设定停顿时间的目标,相比于CMS,G1未必能做到CMS在最好情况下的延时停顿,但是最差情况要好很多;
- 避免内存碎片:“标记-整理”算法的好处,尤其是当 Java 堆非常大的时候,G1 的优势更加明显。
缺点
- G1 需要Remembered Set (卡表)来记录引用关系,这种数据结构占用大量内存,可能达到整个堆内存容量的 20% 甚至更多。
G1和CMS的区别
- G1从整体上来看是 标记-整理 算法,但从局部(两个Region之间)是标记-复制算法。而CMS是 标记-清除算法。G1不会产生内存碎片,而CMS会产生内存碎片;
- CMS使用了 写后屏障来维护卡表,而G1不仅使用了写后屏障来维护卡表,还是用了 写前屏障来跟踪并发时的指针变化情况(为了实现原始快照);
- CMS对Java堆内存使用的是传统的新生代和老年代划分方法,而G1使用的全新的Region划分方法;
- CMS收集器只收集老年代,可以配合新生代的Serial和ParNew收集器一起使用;G1收集器收集范围是老年代和新生代,不需要结合其他收集器;
- CMS使用 增量更新解决并发标记下出现的错误标记问题,而G1使用原始快照解决;
- 按照《深入理解Java虚拟机》作者说法,CMS 在小内存应用上的表现要优于 G1,而大内存应用上 G1 更有优势,大小内存的界限是6~8GB。
什么情况下应该考虑使用G1
官方文档:
- 实时数据占用超过一半的堆空间;
- 对象分配或者晋升的速度变化大;
- 希望消除长时间的GC停顿(超过0.5-1秒);
- 内存大于8GB。