美文网首页JavaJavaer
JVM垃圾收集器

JVM垃圾收集器

作者: AnLingYi | 来源:发表于2019-07-29 20:56 被阅读1次

    原文地址:https://xeblog.cn/articles/24

    image

    新生代收集器

    新生代均采用 复制 算法来回收内存。

    Serial 收集器

    最基本的、发展历史最悠久的单线程的收集器。在进行垃圾收集时,必须暂停其它所有的工作线程(Stop The World),直到它收集结束。它是 JVM 运行在 Client 模式下的默认新生代收集器,它比其它单线程的收集器更简单、更高效。可与 CMS 收集器 配合工作。

    ParNew 收集器

    Serial 收集器 的多线程版本。它是许多运行在 Server 模式下的虚拟机首选的新生代收集器,在使用 -XX:+UseConcMarkSweepGC 选项后的默认新生代收集器,也可以通过 -XX:+UseParNewGC 选项强制指定它。它除了是多线程收集之外,其它和 Serial 收集器 基本一样,它默认开启的收集线程数与 CPU 的数量相同,在 CPU 非常多的环境下,可通过 -XX:ParallelGCThreads 参数限制垃圾收集的线程数。可与 CMS 收集器 配合工作。

    Parallel Scavenge 收集器

    并行的多线程收集器,它的目标是达到一个可控的吞吐量(吞吐量是 CPU 用于运行用户代码的时间与 CPU 总消耗时间的比值)。

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

    高吞吐量可以高效的利用 CPU 时间,尽快的完成程序的运算任务,主要适合在后台运算而不需要太多交互的任务。Parallel Scavenge 收集器 提供了两个参数用于精确控制吞吐量: -XX:MaxGCPauseMillis-XX:GCTimeRatio

    最大垃圾收集停顿时间:-XX:MaxGCPauseMillis

    允许一个大于0的毫秒数,收集器将尽可能保证内存回收花费时间不超过这个设定的值,它是以牺牲吞吐量和新生代空间来缩短 GC 停顿时间的。

    吞吐量大小:-XX:GCTimeRatio

    允许一个大于0且小于100的整数,垃圾收集时间占总时间的比率。

    GC自适应调节参数:-XX:+UseAdaptiveSizePolicy

    这是一个开关参数,当它打开后,就不需要手动指定新生代的大小(-Xmn),EdenSurvivor 区的比例(-XX:SurvivorRatio)、晋升老年代对象年龄(-XX:PretenureSizeThreshold)等细节参数了,虚拟机会根据当前系统的运行情况收集性能监控信息,动态调整这些参数以提供最合适的停顿时间或最大的吞吐量。

    老年代收集器

    老年代采用 标记-整理标记-清除 算法来回收内存。

    Serial Old 收集器

    它是 Serial 收集器 的老年代版本,也是一个单线程收集器,使用 标记-整理 算法。这个收集器的主要意义也是在于给 Client 模式下的虚拟机使用,如果是在 Server 模式下,那么它主要还有两大用途:

    • JDK1.5 以及之前版本中与 Parallel Scavenge 收集器 搭配使用。
    • 作为 CMS收集器 的后备预案,在并发收集发生 Concurrent Mode Failure 时使用。

    Parallel Old 收集器

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

    CMS 收集器 (Concurrent Mark Sweep)

    它是一种并发的、以获取最短回收停顿时间为目标的收集器,使用 标记-清除 算法实现的。运行过程较为复杂,整个过程分为4个步骤:

    • 初始标记(CMS Initial Marking)
    • 并发标记(CMS Concurrent marking)
    • 重新标记(CMS ReMarking)
    • 并发清除(CMS Concurrent Sweep)

    初始标记、重新标记仍需要暂停其它所有的工作线程,初始标记仅仅只是标记一下 GC Roots 能直接关联到的对象,速度很快。并发标记阶段就是进行 GC Roots 的可达性分析过程,而重新标记阶段则是为了修正并发标记期间因用户线程继续运作而导致标记产生变动的那一部分对象的标记记录,这个阶段的停顿时间一般会比初始标记阶段稍长一些,但远比并发标记的时间短。CMS 收集器 存在3个明显的缺点:

    • CMS收集器 会占用一部分线程而导致应用程序变慢,总吞吐量会降低。CMS 默认启功的回收线程数是(CPU数量 + 3)/ 4 ,相当于当 CPU 在4个以上时,并发回收时垃圾收集线程不少于 25%CPU 资源,并随着 CPU 数量的增加而下降。当 CPU 不足4个时,CMS 对用户线程的影响就可能变得更大。
    • CMS收集器 无法处理浮动垃圾,可能出现 Concurrent Mode Failure 失败而导致另一次 Full GC 的产生。由于 CMS 并发清除阶段用户线程还在运行着,伴随程序运行自然就还会有新的垃圾不断产生,这一部分垃圾出现在标记过程之后,CMS 无法在当次收集中处理掉它们,只好留在下一次 GC 时再清理掉,这一部分垃圾就称为浮动垃圾。
    • 由于 CMS收集器 使用的是 标记-清除 算法,所以垃圾回收后会产生大量的空间碎片。CMS 提供 -XX:+UseCMSCompactAtFullCollection 的开关参数(默认开启),用于在 CMS 收集器顶不住要进行 Full GC 时开启内存碎片的合并整理过程,这个过程是无法并发执行的,虽然空间碎片没了,但是停顿时间不得不变长。

    全干工程师:G1收集器

    G1收集器 是当今收集器技术发展的最前沿成果之一。

    上面所介绍的收集器,都只是负责 Java堆 中的一部分内存(新生代或老年代),而 G1 就不同了,它全干。
    G1 将整个 Java堆 划分为多个大小相等的独立区域(Region),虽然还保留有新生代和老年代的概念,但是这两部分内存不再是物理隔离的,它们都是一部分不需要连续的 Region 的集合了。

    具备的特点:

    • 并行与并发:G1 能充分利用多 CPU 、多核环境下的硬件优势,使用多个 CPU 来缩短 Stop The World 的停顿时间。
    • 分代收集(全干工程师):G1 可以不需要与其它收集器配合就能独立管理整个 GC堆,根据 分代收集 的概念采用不同的方式去处理。
    • 空间整合:基于 标记-整理复制 算法,不会产生内存空间碎片。
    • 可预测的停顿:G1 可以建立可预测的停顿时间模型,将垃圾收集消耗的时间限制在一定的时间内。

    可预测的停顿时间模型

    G1 之所以能够建立可预测的停顿时间模型,是因为它可以有计划的避免在整个 Java堆 中进行全区域的垃圾收集。G1 通过跟踪各个 Region 里面的内存堆积的价值大小(回收所获得的空间大小以及回收所需时间的经验值),在后台维护一个优先回收队列,每次根据允许的收集时间,优先回收价值最大的 Region。这种使用 Region 划分内存空间以及有优先级的区域回收方式,保证了 G1 收集器在有限的时间内可以获取尽可能高的收集效率。

    避免全堆扫描且保证准确性

    G1 收集器中,Region 之间的对象引用以及其它收集器中的新生代与老年代之间的对象引用,虚拟机都是使用 Remembered Set 来避免全堆扫描的。G1 中的每一个 Region 都有一个与之对应的 Remembered Set,在对 Reference 类型的数据进行写操作的时间,虚拟机会产生一个屏障暂时中断写操作,然后检查这个引用的对象是否处于不同的 Region 之中,如果是,就会通过 CardTable 把相关引用信息记录到被引用对象所属的 RegionRemembered Set 中。当进行内存回收时,在 GC Roots 的枚举范围内加入 Remembered Set 即可保证不对全堆扫描也不会有遗漏。

    G1运行过程

    如果不计算维护 Remembered Set 的操作,G1 收集器的运行过程大致可以分为4个步骤:

    • 初始标记(G1 Initial Marking)
    • 并发标记(G1 Concurrent Marking)
    • 最终标记(G1 Final Marking)
    • 筛选回收(G1 Live Data Counting And Evacuation)

    初始标记阶段只是简单的标记一下 GC Roots 能直接关联到的对象,并且修改TAMS(Next Top At Mark Start)的值,让下一阶段用户程序并发运行时,能在正确可用的 Region 中创建新对象,这个阶段需要停顿线程,但耗时很短。并发标记阶段也是进行 GC Roots 的可达性分析过程,耗时很长但是可与用户程序一起工作。最终标记阶段是为了修正并发标记期间因用户线程继续运作而导致标记产生变动的那一部分对象的标记记录,虚拟机将这段时间对象变化记录在线程的 Remembered Set Logs 中,这个阶段需要把 Remembered Set Logs 中的数据合并到 Remembered Set 里,需要停顿线程,但是可以并行执行。
    最后的筛选回收阶段会对 Region 的回收价值和成本进行排序,根据用户所期望的 GC 停顿时间来制定回收计划。

    查看JVM所使用的收集器

    java -XX:+PrintCommandLineFlags -version
    

    在终端执行上述命令后,即可查看 JVM 所使用的收集器。

    image

    -XX:+UseParallelGC : 是虚拟机运行在 Server 模式下的默认值,打开此开关后,使用 Parallel Scavenge + Serial Old (PS MarkSweep) 的收集器组合进行内存回收。

    参考

    • 《深入理解Java虚拟机:JVM高级特性与最佳实践 第二版》

    相关文章

      网友评论

        本文标题:JVM垃圾收集器

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