JVM 垃圾收集器Serial +Serial Old+ParNew+Parallel Scavenge+Parallel Old+CMS+G1

版权声明:本文为博主原创文章,未经博主允许不得转载。 https://blog.csdn.net/zhou920786312/article/details/84276583

这里写图片描述

 

1 Seiral 收集器

特征

  1. 是单线程的
  2. 在垃圾回收时,必须暂停其他所有线程的工作线程,即所谓的“Stop The World”
  3. jvm在Client模式下,默认的新生代收集器仍然是Serial收集器,虽然它有着上述两个重大的缺点,但也有这简单高效的优点。
    1. 单线程,没有线程交互开销
  4. 使用方法:-XX:+UseSerialGC
  5. 适用:运行在Client模式下的虚拟机。

Serial和Serial Old的协同工作模式

这里写图片描述

2 Serial Old收集器

特征

  • Serial Old是单线程,使用标记整理算法Serial老年代版本,主要意义也是在于给Client模式下的虚拟机使用。

  • Server模式下用途:
    • 在JDK1.5以及之前的版本中与Parallel Scavenge收集器搭配使用
    • 当老年代使用CMS收集器出现故障时(Concurrent Mode Failure),可以作为CMS的后备选择。 

Serial和Serial Old的协同工作模式

这里写图片描述

3 ParNew 收集器

特征

  1. 其实就是Serial收集器的多线程版本,除了使用多条线程进行垃圾收集之外,其余的和Serial所有控制参数一样。
  2. 在配置为CMS 收集器的默认新生代收集器。
  3. 在多CPU的环境下可以发挥更高而效率,并且是唯一一个可以和CMS收集器搭配工作的新生代并行GC。
  4. 单CPU的环境下效率低于Serial
  5. 适用:运行在server模式下的虚拟机首选的新生代收集器。
  6. 使用方法:-XX:+UseParNewGC

这里写图片描述

Parallel Scavenge(并行回收)收集器

特征

  1. 新生代收集器
  2. 使用复制算法,并行的多线程收集器
  3. 控制的吞吐量
    1. 吞吐量=运行用户代码时间/(运行用户代码时间+垃圾收集时间)
  4. 停顿时间越短就越适合需要与用户交互的程序,良好的响应速度能提升用户体验,而高吞吐量则可用高效率地利用CPU时间,尽快完成程序的运算任务,主要适合在后台运算而不需要太多交互的任务。

  5. 参数:

    1. -XX:MaxGCPauseMillis:控制最大垃圾收起停顿时间(毫秒)。

      1. 收集器会尽可能的保证每次垃圾收集耗费的时间不超过这个设定值。但是如果这个这个值设定的过小,那么Parallel Scavenge收集器为了保证每次垃圾收集的时间不超过这个限定值,会导致垃圾收集的次数增加和增加年轻代的空间大小,垃圾收集的吞吐量也会随之下降。

      2. 注意: XX:MaxGCPauseMillis设置的越小,吞吐量则必然越小。

    2. -XX:GCTimeRatio: 设置吞吐量大小(>0,<100)。默认值为99,即最大允许1%的垃圾收集时间。

      1. 是应用程序运行时间和垃圾收集时间的比值。如果把值设置为19,即系统运行时间 : GC收集时间 = 19 : 1,那么GC收集时间就占用了总时间的5%【1 / (19 + 1) = 5%】,

    3. -XX:+UseAdaptiveSizePolicy:

      1. 当这个参数打开之后,就不需要手工指定新生代的大小、Eden与Survivor区的比例、晋升老年代对象年龄等细节参数了,虚拟机会根据当前系统的运行情况收集性能监控信息,动态调整这些参数以提供最合适的停顿时间或者最大的吞吐量,这种调节方式称为GC自适应的调节策略(GC Ergonomics)。

      2. 只需要把基本的内存数据设置好(如-Xmx设置最大堆),然后使用MaxGVPauseMillis参数或GCTimeRation参数给虚拟机设立一个优化目标,JVM会自动调节其他优化参数.

      3. 自适应调节策略也是Parallel Scavenge收集器与ParNew收集器的一个重要区别

  6. Parallel Scavenge要和Parallel Old一起使用

Parallel Scavenge/Parallel Old运行示意图

这里写图片描述

5 Parallel Old 收集器

特征

  1. 是Parallel Scavenge收集器的老年代版本,使用多线程和“标记-整理”算法。
  2. 参数控制: -XX:+UseParallelOldGC 
  3. 只能和Parallel Scavenge配合使用,这个组合常用于注重吞吐量以及CPU资源敏感的场合。 

Parallel Scavenge/Parallel Old运行示意图

这里写图片描述

6 CMS(Concurrent Mark Sweep)收集器

特征

  1. 一种以获取最短回收停顿时间为目标的收集器。

  2. 适用于 :重视服务的响应速度,希望系统停顿时间最短,以给用户带来较好的体验的应用。

  3. CMS收集器是基于“标记-清除”算法实现的,

  4. 运作过程分为4个步骤:

    1. 初始标记(CMS initial mark)
      1. 需要“Stop The World”,仅仅只是标记一下GC Roots能直接关联到的对象,速度很快。
    2. 并发标记(CMS concurrent mark)

      1. 就是进行GC Roots Tracing(跟踪)的过程。(就是判断哪些对象不可达的过程)。

      2. 与用户线程一起工作。

    3. 重新标记(CMS remark)

      1. 需要“Stop The World”,是为了修正并发标记期间,因用户程序继续运作而导致标记产生变动的那一部分对象的标记记录,这个阶段的停顿时间一般会比初始标记阶段稍长一些,但远比并发标记的时间短。

    4. 并发清除(CMS concurrent sweep)

      1. 与用户线程一起工作。

  5.  总体上来说,CMS收集器的内存回收过程是与用户线程一起并发地执行。 

  6.  优点:并发收集、低停顿。

  7.  缺点:
    1. CMS收集器对CPU资源非常敏感。对于并发实现的收集器而言,虽然可以利用多核优势提高垃圾收集的效率,但是由于收集器在运行过程中会占用一部分的线程,这些线程会占用CPU资源,所以会影响到应用系统的运行,会导致系统总的吞吐量降低。CMS默认开始的回收线程数是(cpu数量 + 3) / 4,所以,当机器的CPU数量为4个以上的时候,垃圾回收线程将占用不少于%25的CPU资源,并且随着CPU数量的增加,垃圾回收线程占用的CPU资源会减少。但是,当CPU资源少于4个的时候,垃圾回收线程占用的CPU资源的比例会增大,会影响到系统的运行,假设有2个CPU的情况下,垃圾回收线程将会占据超过50%的CPU资源。所以,在选用CMS收集器的时候,需要考虑,当前的应用系统,是否对CPU资源敏感。

    2. 垃圾收集的过程中,无法处理浮动垃圾,所以可能会出现Concurrent Mode Failure问题而导致触发一次Full GC。浮动垃圾:是由于CMS收集器的并发清理阶段,清理线程是和用户线程一起运行,如果在清理过程中,用户线程产生了垃圾对象,由于过了标记阶段,所以这些垃圾对象就成为了浮动垃圾,CMS无法在当前垃圾收集过程中集中处理这些垃圾对象。由于这个原因,CMS收集器不能像其他收集器那样等到完全填满了老年代以后才进行垃圾收集,需要预留一部分空间来保证当出现浮动垃圾的时候可以有空间存放这些垃圾对象。在JDK 1.5中,默认当老年代使用了68%的时候会激活垃圾收集,这是一个保守的设置,如果在应用中老年代增长不是很快,可以通过参数 -XX:CMSInitiatingOccupancyFraction 控制触发的百分比,以便降低内存回收次数来提供性能。在JDK 1.6中,CMS收集器的激活阀值变成了92%。如果在CMS运行期间没有足够的内存来存放浮动垃圾,那么就会导致Concurrent Mode Failure失败,这个时候,虚拟机将启动后备预案,临时启动Serial Old收集器来对老年代重新进行垃圾收集,这样会导致垃圾收集的时间边长,特别是当老年代内存很大的时候。所以对参数-XX:CMSInitiatingOccupancyFraction的设置,过高,会导致发生Concurrent Mode Failure,过低,则浪费内存空间。

    3. 使用的"标记-清除"算法会出现很多内存碎片。过多的内存碎片会影响大对象的分配,会导致即使老年代内存还有很多空闲,但是由于过多的内存碎片,不得不提前触发垃圾Full GC。为了解决这个问题,CMS收集器提供了一个"-XX:+UseCMSCompactAtFullCollection"参数(默认是开启的),用于CMS收集器在必要的时候对内存碎片进行压缩整理。由于内存碎片整理过程不是并发的,所以会导致停顿时间变长。虚拟机还提供了一个-XX:CMSFullGCsBeforeCompaction"参数,来控制进行过多少次不压缩的Full GC以后,进行一次带压缩的Full GC,默认值是0,表示每次在进行Full GC前都进行碎片整理。

  8.  参数
    1. -XX:+UseConcMarkSweepGC:使用CMS收集器
    2.  -XX:+ UseCMSCompactAtFullCollection: Full GC后,进行一次碎片整理;整理过程是独占的,会引起停顿时间变长。 
    3. -XX:+CMSFullGCsBeforeCompaction  设置进行几次Full GC后,进行一次碎片整理。
    4. -XX:ParallelCMSThreads  设定CMS的线程数量(一般情况约等于可用CPU数量) 。

CMS收集器示意图
这里写图片描述

7G1收集器(面向服务端)

 特点:

  1. 并行于并发:使用多个CPU(CPU或者CPU核心)来缩短stop-The-World停顿时间,其他需要停顿Java线程执行的GC动作,G1收集器仍然可以通过并发的方式让java程序继续执行。
  2. 分代收集:虽然G1可以不需要其他收集器配合就能独立管理整个GC堆,但是还是保留了分代的概念。它能够采用不同的方式去处理新创建的对象和已经存活了一段时间,熬过多次GC的旧对象以获取更好的收集效果。
  3. 空间整合:与CMS的“标记--清理”算法不同,G1从整体来看是基于“标记整理”算法实现的收集器;从局部上来看是基于“复制”算法实现的。但无论如何,都意味着G1运作期间不会产生内存空间碎片,收集后能够提供规整的可用内存,这种特性有利于程序长时间运行,分配大对象时不会因为无法找到连续内存空间而提前触发下一次GC。
  4. 可预测的停顿:这是G1相对于CMS的另一大优势,降低停顿时间是G1和CMS共同关注点, 但G1除了追求低停顿外,还能建立可预测的停顿时间模型,能让使用者明确指定在一个长度为M毫秒的时间片段内,消耗在垃圾收集上的时间不得超过N毫秒。

 存储内存结构

 
G1会将堆划分为固定大小的多个区域,名称为Region,每一个Region都有对应一个remembered set(避免全堆扫描,记录每个对象是否可达),依然存在eden,S0,S1,old这些概念,不同的是是采用逻辑区分,而不是物理区分.每个heap区(Region)的大小在JVM启动时就确定了. JVM 通常生成 2000 个左右的heap区, 根据堆内存的总大小,一个Region的大小可以通过参数-XX:G1HeapRegionSize设定,范围允许为 1Mb 到 32Mb,且是2的指数倍。

这里写图片描述

优先列表

 G1跟踪各个region里面的垃圾堆积的价值大小(回收所获得的空间大小以及回收所需时间的经验值),在后台维护一个优先列表,每次根据允许的收集时间,优先回收价值最大的Region。这种使用Region划分内存空间以及有优先级的区域回收方式,保证了G1收集器在有限的时间内可以获取尽可能高的收集效率。
 

运行示意图

这里写图片描述

收集步骤:

1、标记标记(Initial Marking):停顿用户,耗时很短,只是标记一下GC Roots能直接关联到的对象,并且修改TAMS(Next Top At Mark Start)的值,让下一个阶段用户程序并发运行时,能在正确可用的Region中创建新对象。

2 并发标记(Concurrent Marking):GC Root开始对堆中对象进行可达性分析,找出存活的对象,这阶段时耗时较长,但可与用户程序并发执行。

3终标记阶(Final Marking): 为了修正在并发标记期间因用户程序继续运作而导致标记产生变动的那一部分标记记录,虚拟机将这段时间对象变化记录在线程Remenbered Set Logs里面,最终标记阶段需要把Remembered Set Logs的数据合并到Remembered Set中,这一阶段需要停顿线程,但是可并行执行。

4 筛选回收:首先对各个Region的回收价值和成本进行排序,根据用户所期望的GC停顿时间来制定回收计划。

猜你喜欢

转载自blog.csdn.net/zhou920786312/article/details/84276583