JVM中各个垃圾收集器的使用场景

JVM中各个垃圾收集器的使用场景

在以往的文章中(垃圾收集算法),我们讲述了JVM中垃圾收集算法,像标记-清除、标记-整理、复制、分代等算法,这些只是垃圾收集的方法论,今天要介绍的就是垃圾收集的具体实现---垃圾收集器。

垃圾收集器主要用于堆内存中,先从一张图中看下堆中老年代和新生代所适合的垃圾收集器,JDK11出来的ZGC不在其中。

image

Serial、ParNew、Parallel Scavenge用于新生代;CMS、Serial Old、Paralled Old用于老年代。 并且他们相互之间以相对固定的组合使用。G1是一个独立的收集器不依赖其他6种收集器。

1、Serial收集器,是单线程执行垃圾回收的,是JDK1.3之前新生代收集的唯一选择。当需要执行垃圾回收时,程序会暂停一切手上的工作,然后单线程执行垃圾回收。因为新生代的特点是对象存活率低,所以收集算法用的是复制算法,把新生代存活对象复制到老年代,复制的内容不多,性能较好。

2、Serial Old收集器,老年代的收集器,与Serial一样是单线程,不同的是算法用的是标记-整理(Mark-Compact),因为老年代里面对象的存活率高,如果依旧是用复制算法,需要复制的内容较多,性能较差。并且在极端情况下,当存活为100%时,没有办法用复制算法。所以需要用Mark-Compact,以有效地避免这些问题。这个收集器的主要意义也是被Client模式下的虚拟机使用。如果是Server模式下,它的用途有两个:一是在JDK1.5版本及之前版本与Parallel Scavenge收集器搭配使用,另外一个就是CMS收集器的后备预案,在并发收集发生Concurrent Mode Failure使用。

下图是Serial/Serial Old收集器运行示意图:

image

3、ParNew收集器,ParNew同样用于新生代,是Serial的多线程版本,并且在参数、算法(同样是复制算法)上也完全和Serial相同。Par是Parallel的缩写,但它的并行仅仅指的是收集多线程并行,并不是收集和原程序可以并行进行。ParNew也是需要暂停程序一切的工作,然后多线程执行垃圾回收。

4、Parallel Scavenge收集器,新生代的收集器,同样用的是复制算法,也是并行多线程收集。与ParNew最大的不同,它关注的是垃圾回收的吞吐量。这里的吞吐量指的是 总时间与垃圾回收时间的比例。这个比例越高,证明垃圾回收占整个程序运行的比例越小。

5、Parallel Old收集器,老年代的收集器,是Parallel Scavenge老年代的版本。其中的算法替换成Mark-Compact,标记-整理算法。Parallel Old收集器出现后,“吞吐量优先”收集器终于有了比较不错的应用组合,在注重吞吐量及CPU资源敏感的场合,可以优先考虑Parallel Scavenge收集器+Parallel Old收集器。

下图就是Parallel Scavenge/Parallel Old收集器的运行示意图:

image

6、CMS收集器,同样是老年代的收集器。它关注的是垃圾回收最短的停顿时间(低停顿),在老年代并不频繁GC的场景下,是比较适用的。用的是Mark Sweep,标记-清除算法。运行过程一共分为四步:初始标记-并发标记-重新标记-并发清理。其中初始标记和重新标记仍需要STW,不过速度很快,耗时最长的是并发标记和并发清理,由于是并发的执行,效率很高。

下图是CMS收集器运行示意图:

image

7、G1收集器,在JDK 1.7版本正式启用,是当时最前沿的垃圾收集器。G1可以说是CMS的终极改进版,解决了CMS内存碎片、更多的内存空间登问题。虽然流程与CMS比较相似,但底层的原理已是完全不同。高效益优先。G1会预测垃圾回收的停顿时间,原理是计算老年代对象的效益率,优先回收最大效益的对象。堆内存结构的不同。以前的收集器分代是划分新生代、老年代、持久代等。G1则是把内存分为多个大小相同的区域Region,每个Region拥有各自的分代属性,但这些分代不需要连续。

另外:伴随着JDK11的到来,也带来了一款新的垃圾收集器-ZGC,能处理TB级别的堆空间,这是要上天呀,TB级别。不过目前只支持在Linux平台上。ZGC给Hotspot Garbage Collectors增加了两种新技术:着色指针和读屏障,这里不做过多解析。

下面图片给出的是设置垃圾收集常用的参数:

你可能感兴趣的:(JVM中各个垃圾收集器的使用场景)