CMS垃圾收集器

CMS(Concurrent Mark-Sweep)是一个里程碑式垃圾收集器,因为之前的垃圾回收器线程在工作的时候,工作线程是不能工作的,是STW的,而CMS是可以和工作线程同时运行的,CMS主要用于老年代回收,主要算法是标记—清除。

JVM参数加上-XX:+UseConcMarkSweepGC表示老年代垃圾回收器采用CMS

CMS运行过程可以大致分为4个阶段

  1. inital mark
  2. concurrent mark
  3. remark
  4. concurrent sweep

第一个阶段inital mark初始标记
先通过GCroots找到根对象,然后通过根对象找到直接关联的对象,这个阶段会产生STW的,但是因为对象一般不会很多,所以STW时间也很短。
(GCroots的一般是指被线程栈变量,静态变量,常量池,JNI指针所引用的对象)

第二个阶段concurrent mark并发标记
这个阶段垃圾收集器线程是和应用程序线程是发执行的,这个时候应用程序线程可能会不断改变的引用的指向,所以就需要标记很多次,也是最耗时的。因为把最耗时的阶段和工作线程并发运行,所以不需要STW,这样就对用户的响应比较及时。

第三个阶段remark重新标记
这个阶段主要的作用,就是把在并发标记过程,原来是垃圾的对象变成非垃圾对象了,这个时候就需要进行重新标记,这个阶段会产生STW,但是因为这些引用改的不会太多,所以STW的时间很短。

第四个阶段concurrent sweep并发回收
这个阶段垃圾收集器线程是也是和应用程序线程是发执行的,垃圾收集器线程在清理的过程中,这时候产生的垃圾叫做浮动垃圾,只能等待等下一轮回收了

从线程的角度看运行过程

在这里插入图片描述

CMS的优缺点

优点
CMS是以牺牲吞吐量为代价来获得最短回收停顿时间的,所以它的STW时间短,如果对服务器响应速度要求高的话,可以使用这种垃圾回收器。


缺点
因为CMS采用的算法是Mark-Sweep(标记—清除),所以会产生空间碎片。

会产生浮动垃圾,所以需要更大的推空间,因为CMS标记阶段的时候,应用程序的线程还是在执行的。所以就会有堆空间的继续分配的情况,但是为了保证CMS回收堆空间之前,还有空间分配给正在运行的应用程序,所以必须要预留一部分空间,也就是说,CMS不会在老年代满的时候才开始清理,而是会更早的开始清理,默认是当老年代使用68%的时候,CMS垃圾清理就开始了。
CMS是通过-XX:CMSInitiatingOccupancyFraction 来设置这个阀值的



CMS日志分析

执行命令:java -Xms20M -Xmx20M -XX:+PrintGCDetails -XX:+UseConcMarkSweepGC 观察GC日志。

ParNew日志
[GC (Allocation Failure) [ParNew: 6144K->640K(6144K), 0.0265885 secs] 6585K->2770K(19840K), 0.0268035 secs] [Times: user=0.02 sys=0.00, real=0.02 secs] 

ParNew:年轻代收集器
6144K->640K(6144K):6144k是指回收前年轻代的空间大小、640K是指回收后的年轻代空间大小、6144K是指年轻代总空间大小
6585K->2770K(19840K):6585K是指回收前堆空间大小、2770K是指回收后堆空间大小、19840K是指总堆空间大小
CMS日志
 [GC (CMS Initial Mark) [1 CMS-initial-mark: 8511K(13696K)] 9866K(19840K), 0.0040321 secs] [Times: user=0.01 sys=0.00, real=0.00 secs] 
	//8511 (13696) : 老年代使用(最大)
	//9866 (19840) : 整个堆使用(最大)
[CMS-concurrent-mark-start]
[CMS-concurrent-mark: 0.018/0.018 secs] [Times: user=0.01 sys=0.00, real=0.02 secs] 
	//这里的时间意义不大,因为是并发执行
[CMS-concurrent-preclean-start]
[CMS-concurrent-preclean: 0.000/0.000 secs] [Times: user=0.00 sys=0.00, real=0.00 secs] 
	//标记Card为Dirty,也称为Card Marking
[GC (CMS Final Remark) [YG occupancy: 1597 K (6144 K)][Rescan (parallel) , 0.0008396 secs][weak refs processing, 0.0000138 secs][class unloading, 0.0005404 secs][scrub symbol table, 0.0006169 secs][scrub string table, 0.0004903 secs][1 CMS-remark: 8511K(13696K)] 10108K(19840K), 0.0039567 secs] [Times: user=0.00 sys=0.00, real=0.00 secs] 
	//STW阶段,YG occupancy:年轻代占用及容量
	//[Rescan (parallel):STW下的存活对象标记
	//weak refs processing: 弱引用处理
	//class unloading: 卸载用不到的class
	//scrub symbol(string) table: 
		//cleaning up symbol and string tables which hold class-level metadata and 
		//internalized string respectively
	//CMS-remark: 8511K(13696K): 阶段过后的老年代占用及容量
	//10108K(19840K): 阶段过后的堆占用及容量

[CMS-concurrent-sweep-start]
[CMS-concurrent-sweep: 0.005/0.005 secs] [Times: user=0.00 sys=0.00, real=0.01 secs] 
	//标记已经完成,进行并发清理
[CMS-concurrent-reset-start]
[CMS-concurrent-reset: 0.000/0.000 secs] [Times: user=0.00 sys=0.00, real=0.00 secs]
	//重置内部结构,为下次GC做准备

Card Table的概念

由于做YGC时,需要扫描整个OLD区,效率非常低,所以JVM就设计了CardTable, 如果一个OLD区Card中有对象指 向Y区,就将它设为Dirty,下次扫描时,只需要扫描Dirty Card,在结构上,Card Table用BitMap来实现。

CMS常用参数

  • -XX:+UseConcMarkSweepGC
  • -XX:ParallelCMSThreads
    CMS线程数量
  • -XX:CMSInitiatingOccupancyFraction
    使用多少比例的老年代后开始CMS收集,默认是68%(近似值),如果频繁发生SerialOld卡顿,应该调小,(频繁CMS回收)
  • -XX:+UseCMSCompactAtFullCollection
    在FGC时进行压缩
  • -XX:CMSFullGCsBeforeCompaction
    多少次FGC之后进行压缩
  • -XX:+CMSClassUnloadingEnabled
  • -XX:CMSInitiatingPermOccupancyFraction
    达到什么比例时进行Perm回收
  • GCTimeRatio
    设置GC时间占用程序运行时间的百分比
  • -XX:MaxGCPauseMillis
    停顿时间,是一个建议时间,GC会尝试用各种手段达到这个时间,比如减小年轻代
  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值