美文网首页
JVM垃圾收集器

JVM垃圾收集器

作者: 史啸天 | 来源:发表于2019-11-24 12:55 被阅读0次

    概述

        如果说收集算法是内存回收的方法论,那么垃圾收集器就是内存回收的具体实现。不同厂商、不同版本的虚拟机所提供的垃圾收集器都可能会有很大差别,这里讨论的收集器基于HotSpot虚拟机。如下图所示:


    HotSpot虚拟机的垃圾收集器.png

        以上7种作用于不同分代的收集器,如果两个之间存在连线,就说明它们可以搭配使用。截止目前仍然没有哪一个是最好的收集器,更加没有万能的收集器,所以我们选择的只是对具体应用最合适的收集器。

    Serial收集器

        Serial收集器是最基本、发展历史最悠久的收集器,曾经(JDK1.3.1之前)是虚拟机新生代收集的唯一选择。
        这个收集器是一个单线程的收集器,这里所说的“单线程”并不仅仅说明它只会使用一个CPU或一条收集线程工作,更重要的是它进行垃圾收集时,必须暂停所有的工作线程,直到收集结束(Stop The World,这个名词听起来非常酷)。
        对于“Stop The World”带给用户的不良体验,虚拟机的设计者们表示完全理解,因为“你妈妈再给你打扫房间的时候,肯定也会让你老老实实地在椅子上或者房间外待着,如果她一边打扫,你一边乱扔纸屑,这房间还能打扫完?”
        看到这里读者似乎已经把Serial收集器描述成一个“老而无用、食之无味弃之可惜”的鸡肋了,但实际到现在为止,他依然是虚拟机运行在Client模式下的默认新生代收集器。因为它:简单而高效,对于收集几十兆甚至一两百兆的新生代,停顿时间完全可以控制在几十毫秒最多一百多毫秒以内,只要不频繁发生,这点停顿完全是可以接受的。

    ParNew收集器

        ParNew收集器其实就是Serial收集器的多线程版本,除了使用多条线程进行垃圾收集之外,其余行为几乎完全一样,实现上,这两种收集器也共用了相当多的代码。

    Parallel Scavenge收集器

        Parallel Scavenge收集器也是一个新生代收集器,它也是使用复制算法的收集器,又是并行多线程收集器。
        然而Parallel Scavenge收集器与其他收集器不同,它的目标则是达到一个可控制的吞吐量(Throughput)。所谓吞吐量就是CPU用于用户代码的时间与CPU总消耗的比值。大概公式如下

    吞吐量 = 运行用户代码时间 / (运行用户代码时间 + 垃圾收集时间)
    

        Parallel Scavenge收集器也经常被称为“吞吐量优先”收集器。

    Serial Old收集器

        Serial Old是Serial收集器的老年代版本,它同样是一个单线程收集器,使用“标记-整理”算法。这个收集器主要意义也是在于给Client模式下的虚拟机使用。

    Paraller Old

        Parallel Old是Parallel Scavenge收集器的老年代版本,使用多线程和“标记-整理”算法。

    CMS收集器

        CMS(Concurrent Mark Sweep)收集器是一种以获得最短回收停顿时间为目标的收集器。它基于“标记-清除”算法实现的,它的运作过程相对于前面几种收集器来说更复杂一些。收集过程如下:
        1、初始标记(CMS initial mark)
        2、并发标记(CMS concurrent mark)
        3、重新标记(CMS remark)
        4、并发清除(CMS concurrent sweep)
        其中,初始标记和重新标记这两个步骤仍然需要“Stop The World”。初始标记仅仅只是标记一下GC Roots能直接关联到的对象,速度很快;并发标记阶段就是进行GC Roots Tracing的过程,而重新标记阶段则是为了修正并发标记期间因用户程序继续运作而导致标记产生变动的那一部分。
        CMS是一款优秀的收集器,它的主要优点是并发收集和低停顿。但是CMS还是远远达不到完美的程度,它有以下3个明显缺点:
        1、CMS收集器对CPU资源非常敏感,在并发阶段,它虽然不会导致用户线程停顿,但是会因为占用了一部分线程而导致应用程序变慢。
        2、CMS是一款基于“标记-清除”算法实现的收集器,也就意味着收集结束时会产生大量空间碎片。
        3、CMS收集器无法处理浮动垃圾(Floating Garbage),可能出现“Concurrent Mode Failure”失败而导致另一次Full GC的产生。
        由于CMS并发清除阶段用户线程还在运行,伴随程序运行自然还会有新的垃圾不断产生,这一部分垃圾就是“浮动垃圾”。也是由于垃圾收集阶段用户线程还需要运行,那也就是还需要预留足够的内存空间给用户线程使用,因此CMS收集器不能像其他收集器那样等老年代几乎完全被填满了再进行收集。当然如果CMS运行期间预留的内存无法满足程序需要,这时虚拟机将启动后备预案,临时启动Serial Old收集器来重新进行老年代的垃圾收集,这样停顿时间更长了。

    G1收集器

        G1(Garbage-First)收集器是当今收集器技术发展最前沿成果之一。G1也是一款面向服务端应用的垃圾收集器。G1收集器具备以下特点:
        1、并行与并发;
        2、分代收集;
        3、空间整合,“标记-整理”算法;
        4、可预测的停顿;
        G1收集器收集范围是不再是整个新生代或者老年代,而将整个Java堆划分为多个大小相等的独立区域(Region),虽然还保留有新生代和老年代的概念,但新生代和老年代不再是物理隔离,而是Region(不需要连续)的集合。
        G1把内存“化整为零”的思路,可以有效的建立可预测的停顿时间模型,这样它可以有计划地避免在整个Java堆中进行全区域垃圾收集。

    总结

        今天为大家介绍了比较流行的7种收集器,这些收集器都是在虚拟机中可供选择和设置的收集器。那么接下来我们需要探讨一下JDK默认采用哪种收集器呢?
        话不多说,直接上命令:java -XX:+PrintCommandLineFlags -version如下图所示:


    JDK1.8参数信息.jpg

        红框中内容可以看到“UseParallelGC”,即为Parallel Scavenge + Serial Old,有兴趣的同学可以看看自己装的JDK默认是用的哪种虚拟机,下面为大家奉上收集器对应的别名和参数,以供参考。如下图所示:


    JVM参数.png

    相关文章

      网友评论

          本文标题:JVM垃圾收集器

          本文链接:https://www.haomeiwen.com/subject/nzklwctx.html