当前位置:   article > 正文

JVM中CMS垃圾收集器的介绍-刘宇_cms generation total是什么意思

cms generation total是什么意思

作者:刘宇
CSDN博客地址:https://blog.csdn.net/liuyu973971883
有部分资料参考,如有侵权,请联系删除。如有不正确的地方,烦请指正,谢谢。

一、什么是CMS收集器

1.1、简单介绍

CMS(Concurrent Mark Sweep)收集器,以获取最短回收停顿时间为目标,多数应用与互联网或者B/S系统的服务器端上。
CMS是基于“标记-清除”,算法实现的,整个过程分为4个步骤:

  • 初始标记(CMS initial mark):

    需要Stop The world,只是标记一下GC Roots能直接关联到的对象,速度很快。

  • 并发标记(CMS concurrent mark):

    它是GC Roots Tracing的过程

  • 重新标记(CMS remark):

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

  • 并发清除(CMS concurrent sweep)

1.2、CMS收集器示意图

CMS收集器的运作步骤如下图所示,在整个过程中耗时最长的并发标记和并发清除过程收集器线程都可以与用户线程一起工作,因此,从总体上看,CMS收集器的内存回收过程是与用户线程一起并发执行的。

在这里插入图片描述

1.3、CMS优点

并发收集、底停顿,Oracle公司的一些官方文档中也称之为并发底停顿收集器(Concurrent Low Pause Collector)

1.4、CMS的缺点及解决方法

  • CMS收集器对CPU资源非常敏感。
  • CMS收集器无法处理浮动垃圾(Floating Garbage),可能出现“Concurrent Mode Failure”失败而导致另一次Full GC的产生,此时就会使用后备预案进行收集。如果在应用中老年代增长不是太快,可以适当调高参数-XX:CMSInitiatingOccupancyFraction(当老年代达占用到百分之多少时进行Full GC,默认-1)的值来提高触发百分比,它需要搭配-XX:+UseCMSInitiatingOccupancyOnly来使用,以便降低内存回收次数从而获取更好的性能。要是CMS运行期间预留的内存无法满足程序需要时,虚拟机将启动后备预案:临时启用Serial Old收集器来重新进行老年代的垃圾收集,这样停顿时间就很长了。所以说参数-XX:CMSInitiatingOccupancyFraction设置得太高很容易导致大量“Concurrent Mode Failure”失败,性能反而降低。
  • 收集结束时会有大量空间碎片产生,空间碎片过多时,将会给大对象分配带来很大麻烦,往往会出现老年代还有很大空间剩余,但是无法找到足够大的连续空间来分配当前对象,不得不提前进行一次Full GC。CMS收集器提供了一个-XX:+UseCMSCompactAtFullCollecton开关参数(默认开启),用于在CMS收集器顶不住要进行Full GC时开启内存碎片的合并整理过程,内存整理的过程无法并发,空间碎片问题没有了,但是停顿时间将会边长。-XX:+UseCMSCompactAtFullCollecton与-XX:CMSFullGCsBeforeCompaction(设置成n)搭配使用,每隔n次真正的full GC做一次压缩,这会减少full GC压缩的次数,节省了gc时间
  • 对于堆比较大的应用,GC的时间难以预估。

1.5、空间分配担保

在发生Minor GC之前,虚拟机会先检查老年代最大可用的连续空间是否大于新生代所有对象总空间,如果这个条件成立,那么Minor GC可以确保是安全的。当大量对象在Minor GC后仍然存活,就需要老年代进行空间分配担保,把Survivor无法容纳的对象直接进入老年代。如果老年代判断到剩余空间不足(根据以往每一次回收晋升到老年代对象容量的平均值作为经验值),则进行一次Full GC。

二、CMS的详细步骤

2.1、Phase1:Initial Mark

这个是CMS两次Stop The World事件的其中一次,这个阶段的目标是:标记哪些直接被GC Root引用或者被年轻代存活对象引用的所有对象

在这里插入图片描述

2.2、Phase2:Concurrent Mark

在这个阶段Garbage Collector(垃圾收集器)会遍历老年代,然后标记所有存活的对象,它会根据上一个阶段找到的GC Roots遍历查找。并发标记阶段,它会与用户的应用程序并发运行。并不是老年代所有的存活对象都会被标记,因为在标记期间用户的程序可能会改变一些引用。

在这里插入图片描述

在上面的图中,与阶段1的图进行对比,你就会发现有一个对象的引用已经发生了变化。

2.3、Phase3:Concurrent Preclean

这也是一个并发阶段,与应用的线程并发运行,并不会stop应用的线程。在并发运行的过程中,一些对象的引用可能会发生变化,但是这种情况发生时,JVM会将包含这个对象的区域(Card)标记为Dirty,这也就是Card Marking
在pre-clean阶段,那些能够从Dirty对象到达的对象也会被标记,这个标记做完之后,dirty card标记就会被清除了。

在这里插入图片描述

在 preclean 执行后,dirty card 被清理,被修改的引用信息也被更新。

在这里插入图片描述

2.4、Phase4:Concurrent Abortable Preclean

这也是一个并发阶段,但是同样不会影响用户的应用线程,这个阶段是为了尽量承担STW(stop-the-world)中最终标记阶段的工作。这个阶段持续时间依赖于很多因素,由于这个阶段是在重复做很多相同的工作,直接满足一些条件(比如:重复迭代的次数、完成的工作量或者时钟时间等)

2.5、Phase5:Final Remark

  • 这是第二个STW阶段,也是CMS中的最后一个,这个阶段的目标是标记老年代所有的存活对象,由于之前的阶段是并发执行的,gc线程可能跟不上应用程序的变化,为了完成标记老年代所有存活对象的目标,STW就非常有必要了。
  • 通常CMS的Final Remark阶段会在年轻代尽可能干净的时候运行,目的是为了减少连续STW发生的可能性(因为如果年轻代还存有大量对象时,它们有一部分可能会随之晋升到老年代)这个阶段会比前面的几个阶段更复杂一些。

2.6、Phase6:Concurrent Sweep

这里不需要STW,它是与用户的应用程序并发运行,这个阶段是:清除那些不再使用的对象,回收它们的占用空间为将来使用
在这里插入图片描述

  • 疑问1:既然清除是并发的,如何保证安全呢,如何确保在清除过程中对象的引用不会变化

这里找了很多文章也没有找到是如何保证的,只有一篇关于三色标记的文章似乎能说得通文章1还有这篇讲解了三色标记、浮动垃圾、读写屏障等文章2

  • 疑问2:在清理过程中,新晋升过来的对象如何保证不被清除?

网上有很多答案,有的说CMS在清理的时候要预留一定的空间供用户线程使用,用于存储新生代晋升过来的新对象,保证了在并发清除的时候新对象不会被清除;还有一种在上面的文章1中有介绍到。

2.7、Phase7:Concurrent Reset

这个阶段也是并发执行的,它会重设CMS内部的数据结构,为下次GC做准备

三、CMS练习

JVM运行参数:
-verbose:gc
-Xmx20m
-Xms20m
-Xmn10m
-XX:+PrintGCDetails
-XX:SurvivorRatio=8
-XX:+UseConcMarkSweepGC

代码:

package com.brycen.demo.gc;

public class MyTest5 {
    public static void main(String[] args) {
        int size = 1024*1024;
        byte[] myAlloc1 = new byte[4*size];
        System.out.println("11111");
        byte[] myAlloc2 = new byte[4*size];
        System.out.println("22222");
        byte[] myAlloc3 = new byte[4*size];
        System.out.println("33333");
        byte[] myAlloc4 = new byte[2*size];
        System.out.println("44444");
    }
}
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15

运行结果:

  • 可知CMS是老年代收集器,对应的新生代的收集器是ParNew。
  • 下面详细打印了CMS回收的7个过程。
11111
[GC (Allocation Failure) [ParNew: 6621K->701K(9216K), 0.0040330 secs] 6621K->4799K(19456K), 0.0040867 secs] [Times: user=0.01 sys=0.00, real=0.00 secs] 
22222
[GC (Allocation Failure) [ParNew: 4954K->109K(9216K), 0.0052423 secs] 9052K->8845K(19456K), 0.0052754 secs] [Times: user=0.02 sys=0.00, real=0.01 secs] 
[GC (CMS Initial Mark) [1 CMS-initial-mark: 8736K(10240K)] 12941K(19456K), 0.0002225 secs] [Times: user=0.00 sys=0.00, real=0.00 secs] 
[CMS-concurrent-mark-start]
33333
44444
[CMS-concurrent-mark: 0.001/0.001 secs] [Times: user=0.00 sys=0.00, real=0.00 secs] 
[CMS-concurrent-preclean-start]
[CMS-concurrent-preclean: 0.000/0.000 secs] [Times: user=0.00 sys=0.00, real=0.00 secs] 
[CMS-concurrent-abortable-preclean-start]
[CMS-concurrent-abortable-preclean: 0.000/0.000 secs] [Times: user=0.00 sys=0.00, real=0.00 secs] 
[GC (CMS Final Remark) [YG occupancy: 6575 K (9216 K)][Rescan (parallel) , 0.0057096 secs][weak refs processing, 0.0000137 secs][class unloading, 0.0003602 secs][scrub symbol table, 0.0007289 secs][scrub string table, 0.0002154 secs][1 CMS-remark: 8736K(10240K)] 15311K(19456K), 0.0071343 secs] [Times: user=0.00 sys=0.00, real=0.01 secs] 
[CMS-concurrent-sweep-start]
[CMS-concurrent-sweep: 0.001/0.001 secs] [Times: user=0.00 sys=0.00, real=0.00 secs] 
[CMS-concurrent-reset-start]
[CMS-concurrent-reset: 0.000/0.000 secs] [Times: user=0.00 sys=0.00, real=0.00 secs] 
Heap
 par new generation   total 9216K, used 6739K [0x00000007bec00000, 0x00000007bf600000, 0x00000007bf600000)
  eden space 8192K,  80% used [0x00000007bec00000, 0x00000007bf279818, 0x00000007bf400000)
  from space 1024K,  10% used [0x00000007bf400000, 0x00000007bf41b4b0, 0x00000007bf500000)
  to   space 1024K,   0% used [0x00000007bf500000, 0x00000007bf500000, 0x00000007bf600000)
 concurrent mark-sweep generation total 10240K, used 8735K [0x00000007bf600000, 0x00000007c0000000, 0x00000007c0000000)
 Metaspace       used 3200K, capacity 4496K, committed 4864K, reserved 1056768K
  class space    used 355K, capacity 388K, committed 512K, reserved 1048576K
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21
  • 22
  • 23
  • 24
  • 25
  • 26
声明:本文内容由网友自发贡献,不代表【wpsshop博客】立场,版权归原作者所有,本站不承担相应法律责任。如您发现有侵权的内容,请联系我们。转载请注明出处:https://www.wpsshop.cn/w/我家小花儿/article/detail/561941
推荐阅读
相关标签
  

闽ICP备14008679号