写点什么

CMS 垃圾收集器

用户头像
张sir
关注
发布于: 2021 年 04 月 08 日
CMS垃圾收集器

一、如何使用

  • 1999 年 jdk1.3.1 发布了 serial GC 收集器

  • 2002 年 jdk1.4 发布,Parallel GC 和 CMS 一起发布

  • Parallel GC 在 JDK6 之后成为 Hotspot 默认垃圾收集器


serial GC、ParallelGC、CMS 之间比较:

  • 如果你想最小化的使用内存和并行开销,请选用 serial GC

  • 如果你想最大化应用的吞吐量,请使用 Parallel

  • 如果你想最小化 GC 的中断或停顿时间,请选用 CMS


开启方式:

  • 使用 serial:-XX:+UseSerialGC

  • 使用 ParNew:-XX:+UseParNewGC (老年代使用 serial Old)

  • 使用 Parallel:-XX:+UseParallelGC (PS + serial Old)、-XX:+UseParallelOldGC (PS + PS Old)

  • 使用 CMS:-XX:UseConcMarkSweepGC (年轻代使用 ParNew)


二、回收流程

1、初始标记

会发生 STW,仅仅标记 GC ROOT,过程非常快。容易理解

2、并发标记

此阶段是根据 GC ROOT 全堆 Trace 的过程,与用户线程并发执行。

此阶段可能会产生三个问题:

首先需要明白一个东西:CMS 回收是针对老年代的:

老年的的对象有两个来源:

1)由新生代晋升而来

2)大对象直接分配在老年代。由 -XX:PretenureSizeThreshold 控制

a、如果用户程序产生了新的引用(比如在栈上产生了一个 GC ROOT),怎么办?

此时这个对象会被直接分配到 CMS 预留的空间中。这个空间不会发生 GC。

b、如果已经标记完成的对象、指向了一个新的引用怎么办?

通过写屏障记录新产生的引用,重新标记阶段会以其为 GC ROOT 重新扫描

c、如果已经标记完的对象,删除了一个引用怎么办?

此时 CMS 会不处理这种情况,无用引用,因为已经标记了,所以不会被本次回收。此时是 CMS 的问题:会产生浮动垃圾。

3、重新标记

STW、修正并发标记期间因用户程序产生的对象引用的变更。

4、并发清除

并发清除产生的由 并发标记、重新标记阶段 标记的垃圾。注意:此阶段用户线程也在跑,所以用户线程产生的引用不应该被清理。

三、何时触发 GC

1、Promotion Fail:年轻代晋升失败

2、Comcurrent Mode failure:CMS GC 期间,预留空间不够用户线程使用。通过 -XX:+CMSInitiatingOccupancyFaraction 设置阈值。老年代使用率超过多少会触发 GC。此时是只是老年代 GC,在分代模型中,仅仅这个会发生 Major GC。其余都是 Full GC。


四:缺点

  • 因为 CMS 是多线程的,如果并行开销大的话,会影响用户线程执行

  • 浮动垃圾

  • 内存碎片


四、调优参数

  • -XX:ParallelGCThreads 设置年轻代 ParNew 使用的线程数。默认开启的线程数量与 CPU 核数相同

  • -XX:ConcGCThreads 早期也叫 ParallelCMSThreads。默认为 (ParallelGCThreads + 3) / 4.也就是说 4 核时,CMS 线程数为 1。8 核时,线程数为 2.

  • -XX:+UseCMSCompactAtFullCollection 默认为 0,执行几次 Full GC 以后会进行空间整理。

  • -XX:+CMSInitiatingOccupancyFaraction 默认为 92%,指定老年代使用超过多少一个进行仅限于老年代的回收。


五、增量更新

所谓增量更新就是在并发标记过程中,把赋值的这种新增的引用,做一个集合存起来。在重新标记的时候会找到集合里面的引用然后重新去扫描,再把源头标记为灰色。这就是我们的增量更新。当然,在把我们新增的引用放到集合的时候,会实现一种写屏障的方式。写屏障我们可以理解为在赋值操作的前面加一个方法,赋值的后面做一些操作,也可以理解为 AOP。


用户头像

张sir

关注

路漫漫其修远兮 2018.10.09 加入

还未添加个人简介

评论

发布
暂无评论
CMS垃圾收集器