最近在整理JVM相关的PPT,把CMS算法又过了一遍,每次阅读源码都能多了解一点,继续坚持。

什么是CMS

CMS全称 ConcurrentMarkSweep,是一款并发的、使用标记-清除算法的垃圾回收器, 如果老年代使用CMS垃圾回收器,需要添加虚拟机参数-"XX:+UseConcMarkSweepGC"。

使用场景:

GC过程短暂停,适合对时延要求较高的服务,用户线程不允许长时间的停顿。

缺点:

服务长时间运行,造成严重的内存碎片化。 另外,算法实现比较复杂(如果也算缺点的话)

实现机制

根据GC的触发机制分为:周期性Old GC(被动)和主动Old GC,纯属个人理解,实在不知道怎么分才好。

周期性Old GC

周期性Old GC,执行的逻辑也叫 BackgroundCollect,对老年代进行回收,在GC日志中比较常见,由后台线程ConcurrentMarkSweepThread循环判断(默认2s)是否需要触发。

![](http://5b0988e595225.cdn.sohucs.com/images/20180105/cf3f3579ac5349e2ba590e747ee9ee3a.png)

触发条件

1. 如果没有设置 UseCMSInitiatingOccupancyOnly,虚拟机会根据收集的数据决定是否触发(线上环境建议带上这个参数,不然会加大问题排查的难度)

2. 老年代使用率达到阈值 CMSInitiatingOccupancyFraction,默认92%

3. 永久代的使用率达到阈值 CMSInitiatingPermOccupancyFraction,默认92%,前提是开启 CMSClassUnloadingEnabled

4. 新生代的晋升担保失败

晋升担保失败

老年代是否有足够的空间来容纳全部的新生代对象或历史平均晋升到老年代的对象,如果不够的话,就提早进行一次老年代的回收,防止下次进行YGC的时候发生晋升失败。

周期性Old GC过程

当条件满足时,采用“标记-清理”算法对老年代进行回收,过程可以说很简单,标记出存活对象,清理掉垃圾对象,但是为了实现整个过程的低延迟,实际算法远远没这么简单,整个过程分为如下几个部分:

![](http://5b0988e595225.cdn.sohucs.com/images/20180105/f00d9460aace48f0a20619ca439dcfb2.jpeg)

对象在标记过程中,根据标记情况,分成三类:

1. 白色对象,表示自身未被标记;

2. 灰色对象,表示自身被标记,但内部引用未被处理;

3. 黑色对象,表示自身被标记,内部引用都被处理;

![](http://5b0988e595225.cdn.sohucs.com/images/20180105/bedc5232baf04ff2b03ddfb00be2ac19.png)

假设发生Background Collect时,Java堆的对象分布如下:

![](http://5b0988e595225.cdn.sohucs.com/images/20180105/d6c22b3d52d84c0f9684f97b9c8e9f50.png)

1、InitialMarking(初始化标记,整个过程STW)

该阶段单线程执行,主要分分为两步:

1. 标记GC Roots可达的老年代对象;

2. 遍历新生代对象,标记可达的老年代对象;

该过程结束后,对象分布如下:

![](http://5b0988e595225.cdn.sohucs.com/images/20180105/ff1cc8791896482b9a1cf840eff77aa7.png)

2、Marking(并发标记)

该阶段GC线程和应用线程并发执行,遍历InitialMarking阶段标记出来的存活对象,然后继续递归标记这些对象可达的对象。

因为该阶段并发执行的,在运行期间可能发生新生代的对象晋升到老年代、或者是直接在老年代分配对象、或者更新老年代对象的引用关系等等,对于这些对象,都是需要进行重新标记的,否则有些对象就会被遗漏,发生漏标的情况。

为了提高重新标记的效率,该阶段会把上述对象所在的Card标识为Dirty,后续只需扫描这些Dirty Card的对象,避免扫描整个老年代。

![](http://5b0988e595225.cdn.sohucs.com/images/20180105/09b4a62f5f2e47daa960f64feb27d1e1.jpeg)

3、Precleaning(预清理)

通过参数 CMSPrecleaningEnabled选择关闭该阶段,默认启用,主要做两件事情:

1. 处理新生代已经发现的引用,比如在并发阶段,在Eden区中分配了一个A对象,A对象引用了一个老年代对象B(这个B之前没有被标记),在这个阶段就会标记对象B为活跃对象。

2. 在并发标记阶段,如果老年代中有对象内部引用发生变化,会把所在的Card标记为Dirty(其实这里并非使用CardTable,而是一个类似的数据结构,叫ModUnionTalble),通过扫描这些Table,重新标记那些在并发标记阶段引用被更新的对象(晋升到老年代的对象、原本就在老年代的对象)

4、AbortablePreclean(可中断的预清理)

该阶段发生的前提是,新生代Eden区的内存使用量大于参数CMSScheduleRemarkEdenSizeThreshold默认是2M,如果新生代的对象太少,就没有必要执行该阶段,直接执行重新标记阶段。

为什么需要这个阶段,存在的价值是什么?

因为CMS GC的终极目标是降低垃圾回收时的暂停时间,所以在该阶段要尽最大的努力去处理那些在并发阶段被应用线程更新的老年代对象,这样在暂停的重新标记阶段就可以少处理一些,暂停时间也会相应的降低。

在该阶段,主要循环的做两件事:

1. 处理 From 和 To 区的对象,标记可达的老年代对象

2. 和上一个阶段一样,扫描处理Dirty Card中的对象

当然了,这个逻辑不会一直循环下去,打断这个循环的条件有三个:

1. 可以设置最多循环的次数 CMSMaxAbortablePrecleanLoops,默认是0,表示没有循环次数的限制。

2. 如果执行这个逻辑的时间达到了阈值 CMSMaxAbortablePrecleanTime,默认是5s,会退出循环。

3. 如果新生代Eden区的内存使用率达到了阈值 CMSScheduleRemarkEdenPenetration,默认50%,会退出循环。(这个条件能够成立的前提是,在进行Precleaning时,Eden区的使用率小于十分之一)

如果在循环退出之前,发生了一次YGC,对于后面的Remark阶段来说,大大减轻了扫描年轻代的负担,但是发生YGC并非人为控制,所以只能祈祷这5s内可以来一次YGC。

1. ...

2. 1678.150:\[CMS-concurrent-preclean-start\]

3. 1678.186:\[CMS-concurrent-preclean:0.044/0.055secs\]

4. 1678.186:\[CMS-concurrent-abortable-preclean-start\]

5. 1678.365:\[GC 1678.465:\[ParNew:2080530K->1464K(2044544K),0.0127340secs\]

6. 1389293K->306572K(2093120K),

7. 0.0167509secs\]

8. 1680.093:\[CMS-concurrent-abortable-preclean:1.052/1.907secs\]

9. ....

在上面GC日志中,1678.186启动了AbortablePreclean阶段,在随后不到2s就发生了一次YGC。

5、FinalMarking(并发重新标记,STW过程)

该阶段并发执行,在之前的并行阶段(GC线程和应用线程同时执行,好比你妈在打扫房间,你还在扔纸屑),可能产生新的引用关系如下:

1. 老年代的新对象被GC Roots引用

2. 老年代的未标记对象被新生代对象引用

3. 老年代已标记的对象增加新引用指向老年代其它对象

4. 新生代对象指向老年代引用被删除

5. 也许还有其它情况..

上述对象中可能有一些已经在Precleaning阶段和AbortablePreclean阶段被处理过,但总存在没来得及处理的,所以还有进行如下的处理:

1. 遍历新生代对象,重新标记

2. 根据GC Roots,重新标记

3. 遍历老年代的Dirty Card,重新标记,这里的Dirty Card大部分已经在clean阶段处理过

在第一步骤中,需要遍历新生代的全部对象,如果新生代的使用率很高,需要遍历处理的对象也很多,这对于这个阶段的总耗时来说,是个灾难(因为可能大量的对象是暂时存活的,而且这些对象也可能引用大量的老年代对象,造成很多应该回收的老年代对象而没有被回收,遍历递归的次数也增加不少),如果在AbortablePreclean阶段中能够恰好的发生一次YGC,这样就可以避免扫描无效的对象。

如果在AbortablePreclean阶段没来得及执行一次YGC,怎么办?

CMS算法中提供了一个参数: CMSScavengeBeforeRemark,默认并没有开启,如果开启该参数,在执行该阶段之前,会强制触发一次YGC,可以减少新生代对象的遍历时间,回收的也更彻底一点。

不过,这种参数有利有弊,利是降低了Remark阶段的停顿时间,弊的是在新生代对象很少的情况下也多了一次YGC,最可怜的是在AbortablePreclean阶段已经发生了一次YGC,然后在该阶段又傻傻的触发一次。

所以利弊需要把握。

主动Old GC

这个主动Old GC的过程,触发条件比较苛刻:

1. YGC过程发生Promotion Failed,进而对老年代进行回收

2. System.gc(),前提是添加了-XX:+ExplicitGCInvokesConcurrent参数

如果触发了主动Old GC,这时周期性Old GC正在执行,那么会夺过周期性Old GC的执行权(同一个时刻只能有一种在Old GC在运行),并记录 concurrent mode failure 或者 concurrent mode interrupted。

主动GC开始时,需要判断本次GC是否要对老年代的空间进行Compact(因为长时间的周期性GC会造成大量的碎片空间),判断逻辑实现如下:

1. \*should\_compact =

2. UseCMSCompactAtFullCollection&&

3. ((\_full\_gcs\_since\_conc\_gc >=CMSFullGCsBeforeCompaction)||

4. GCCause::is\_user\_requested\_gc(gch->gc\_cause())||

5. gch->incremental\_collection\_will\_fail(true/\* consult\_young \*/));

在三种情况下会进行压缩:

1. 其中参数 UseCMSCompactAtFullCollection(默认true)和CMSFullGCsBeforeCompaction(默认0),所以默认每次的主动GC都会对老年代的内存空间进行压缩,就是把对象移动到内存的最左边。

2. 当然了,比如执行了 System.gc(),也会进行压缩。

3. 如果新生代的晋升担保会失败。

带压缩动作的算法,称为MSC,标记-清理-压缩,采用单线程,全暂停的方式进行垃圾收集,暂停时间很长很长...

那不带压缩动作的算法是什么样的呢?

不带压缩动作的执行逻辑叫 ForegroundCollect,整个过程相对周期性Old GC来说,少了Precleaning和AbortablePreclean两个阶段,其它过程都差不多。

--转至:http://www.cnblogs.com/aspirant/p/8663911.html

java1.8垃圾回收机制_1.8 CMS垃圾收集器相关推荐

  1. 计算机垃圾回收的过程,计算机体系 – 垃圾收集器

    原标题:计算机体系 – 垃圾收集器 来源:MRRiddler , blog.mrriddler.com/2017/05/01/计算机体系-垃圾收集器/ 继上篇讲述了栈和堆以后,程序已经可以" ...

  2. GC:垃圾回收机制及算法

    GC:垃圾回收机制及算法 关键词 算法:标记(清除/复制/整理).分代收集 收集器(Serial[串行].ParNew[并行].Parallel Scavenge[并行].Serial Old[串行] ...

  3. java垃圾回收机制_JVM的垃圾回收机制——垃圾回收算法

    一.Java垃圾回收机制 在java中,程序员是不需要显示的去释放一个对象的内存的,而是由虚拟机自行执行.在JVM中,有一个垃圾回收线程,它是低优先级的,在正常情况下是不会执行的,只有在虚拟机空闲或者 ...

  4. 36.JVM内存分哪几个区,每个区的作用是什么、如和判断一个对象是否存活、java垃圾回收机制、垃圾收集的方法有哪些、java类加载过程、类加载机制、双亲委派、Minor GC和Major GC

    36.JVM内存分哪几个区,每个区的作用是什么? 37.如和判断一个对象是否存活?(或者GC对象的判定方法) 38.简述java垃圾回收机制? 39.java中垃圾收集的方法有哪些? 40.java类 ...

  5. JVM初学之JVM的垃圾回收机制与垃圾回收器

    如何判断对象是否"已死": 首先,我们要对对象进行垃圾回收之前,就必须要判断对象是否"已死",也就是是否可回收.这里有两种判断逻辑: 引用计数法: 在对象内部维 ...

  6. JVM内存区域(Java内存区域)、JVM垃圾回收机制(GC)初探

    一.JVM内存区域(Java内存区域) 首先区分一下JVM内存区域(Java内存区域)和Java内存模型(JMM)的概念.Java线程之间的通信采用的是共享内存模型,这里提到的共享内存模型指的就是Ja ...

  7. Java 垃圾回收机制算法分析

    垃圾回收机制算法分析 垃圾回收机制概述 垃圾回收简要过程 手动GC回收 finalize作用 内存泄露 如何防止内存泄露 垃圾回收机制算法 引用计数法 复制算法 标记清除算法 标记-压缩算法 分代收集 ...

  8. Java垃圾回收机制总结

    Java垃圾回收机制 垃圾回收(GC,Garbage Collection)是 Java 虚拟机(JVM)垃圾回收器提供的一种用于在空闲时间不定时回收无任何对象引用的对象所占据的内存空间的一种机制.注 ...

  9. 谈谈你对垃圾回收机制的了解?

    一, 垃圾回收机制 在系统运行过程中会产生一些无用的对象,这些对象一直占用内存,不清理这些无用的对象可能会导致内存耗尽,所有垃圾回收机制的是内存. 垃圾收集的原理和概念 对于对象实例收集.主要有两种基 ...

最新文章

  1. 猴子用意念玩游戏,马斯克脑机接口公司新进展
  2. 计算机对英语口语考试成绩,英语口语考试面对“电脑考官” 有何临场技巧
  3. java每秒执行一次_Java性能权威指南
  4. NSLog中格式符列表
  5. IDEA卡顿解决方法
  6. deep_learning 03. tf.nn.rnn_cell.MultiRNNCell()
  7. AIDE手机编程初级教程(零基础向) 3.2.2 设计欢迎页(补充)
  8. 使用暴风激活激活系统,浏览器被劫持问题解决
  9. IDEA 主题颜色设置
  10. pc端js在线预览Word、Excel
  11. JavsScript
  12. mysql ereg_php5.3x不再支持ereg和eregi,解决方法
  13. ACL国际计算机语言协会2019,干货 | 2019 AI 国际顶级学术会议一览表
  14. 细说C++11中ratio编译期分数(一)
  15. 聊聊办公室装修适合哪些风格以及装修技巧
  16. 凉凉!写了个脚本,不小时锁了1W台手机。。
  17. 初学者复现CornerNet:详细指导零基础在Ubuntu系统运行该代码并完全理解论文思路的教程
  18. 复制指定目录后缀文件并重命名
  19. Buildroot中文用户手册
  20. 计算机网络行业规范的主要内容,计算机网络专业论文

热门文章

  1. 开个精品水果店前景怎么样,开一家水果店的前景
  2. win8计算机触摸板怎么设置,win8笔记本电脑怎么设置插入鼠标就自动关闭触摸板...
  3. 建筑CAD制图教程:什么是双跑楼梯?
  4. SVM及LibsvmLiblinear
  5. linux下sigaction函数,Linux sigaction函数 sa_flags的值
  6. 用DCGAN生成卡通人脸
  7. 2023自助洗车店系统解决方案共享洗车无人洗车风口
  8. 【c语言】找出大于m的最小素数,并将其作为函数值返回
  9. 刘帅嵌入式系统-EOR逻辑异或操作指令
  10. 电视应用接入微信登录的那些坑