看看你是如何解释老年代收集器

Serial Old收集器

Serial Old 收集器,也叫串型老年代收集器。Serial Old 的收集器,可以认为是 Serial 收集器的老年代版本,属于多线程收集器,但是它采用的是标记-整理算法。执行过程大致如下图所示:

image.png

可以发现,Serial Old 收集器与 Serial 收集器除使用的算法不同以外,其他和 Serial 收集器都是一样的。

Serial Old 收集器有哪些适用场景呢?Serial Old 收集器可以和 Serial 收集器、ParNew 收集器以及 Parallel Scavenge 收集器这三个新生代的垃圾收集器配合使用(值得一提的是:在 JDK1.5 及之前,与Parallel Scavenge 收集器搭配使用(JDK1.6 有 Parallel Old收集器可搭配 Parallel Scavenge 收集器))。另外如果你的老年代使用的是 CMS 收集器,并且出现故障的时候也会使用 Serial Old 收集器作为后备,作为后备的情况,我们在探讨到c ms收集器的时候,再来详细探讨。

Parallel Old 收集器

Parallel Old 收集器是 Parallel Scavenge 收集器的老生代版本,属于多线程收集器,采用标记-整理算法。Parallel Old 收集器和 Parallel Scavenge 收集器同样考虑了吞吐量优先这一指标,非常适合那些注重吞吐量和 CPU 资源敏感的场合。执行过程大致如下图所示:

image.png

从图中可以发现 Parallel Old 收集器和 Parallel Scavenge 收集器基本上是一样的。

Parallel Old 收集器的特点是它只能和 Parallel Scavenge 配合使用,因此 Parallel Old 收集器适用场景也是关注吞吐量的场景。

CMS 收集器

前面我们讲解的所有收集器要么是串型的,比如 Serial 收集器,Serial Old 收集器,要么是并行的,比如 ParNew 收集器、Parallel Old 收集器 以及 Parallel Scavenge 收集器。那么 CMS 收集器是一款串行收集器。

CMS 英文全称 Concurrent Mark Sweep ,从名称我们就可以分析出来,这是一个并发的收集器,并且它使用的是标记-清除算法。CMS 收集器比前面讲解的垃圾收集器要复杂很多,它的执行过程大致如下图所示:

image.png

第一阶段,初始标记(initial mark)。初始标记用来标记跟根对象能够直接关联到的对象,那么这个阶段会 Stop The World 。不过由于只会标记根对象直接关联到的对象,所以标记的对象相对比较少,停顿的时间还是比较短的。

第二阶段,初始标记完成之后,又会进入并发标记这个阶段,并发标记这个阶段会找到根对象能够关联到的所有对象。在这个阶段下,垃圾收集线程和用户线程并发执行,所以没有 Stop The World。

第三阶段,并发标记完成之后,又会进入一个不一定会执行的阶段,叫做并发预清理。并发预清理会重新标记那些在并发标记阶段引用被更新的对象,比如晋升到老年代的对象,或者原先就在老年代的对象,从而去减少后面重新标记阶段的工作量。这个阶段也是并发执行的,没有 Stop The World,你也可以使用这个参数:-XX:CMSPrecleaningEnabled 去关闭掉这个阶段,默认情况下是打开的。

第四阶段,经过并发预期清理之后,又会进入一个可能会执行也可能不会执行的阶段,叫做并发可终止的预清理阶段。这个阶段做的事情和并发预清理做的事情是一样的,也是为了减少后面重新标记阶段的工作量去设计的,并且没有 Stop The World 状态。并发可终止的预清理阶段要想执行是有前提的,那就是 Eden 的使用量要大于 CMSScheduleRemarkEdenSizeThreshold 阈值,默认是 2M,否则这个阶段会直接跳过。

那么既然已经有了并发预清理的阶段,为什么 CMS 还要再设计一个并发可终止的预清理的阶段呢?我们来看一下并发可终止的预清理阶段它的主要作用是什么?它的主要作用是允许我们能够控制预清理阶段的结束时机,比如你可以控制扫描多长时间就停止这个阶段,可以使用这个参数:-XX:CMSMaxAbortablePrecleanTime 去控制,默认阈值是 5s,或者控制 Eden 的使用比例,达到一定的阈值就结束这个阶段,可以让我们更好的控制 CMS 收集器的行为,可以使用这个参数:CMSScheduleRemarkEdenPenetration 去设置,默认阈值是 50%。

第五阶段,经过并发预清理以及并发可重的预清理,这两个可能会执行也可能不会执行的阶段之后,CMS 会进入重新标记阶段。为什么前面已经有了并发标记还要再弄一个重新标记呢?

这是因为并发标记阶段的标记过程是并发执行的,所以在标记的同时,用户线程可能会修改已经标记过的对象的状态,这样就可能会导致两种情况:

一是,把已经死亡的对象错误的标记成了存活,那这种情况会导致部分垃圾不被回收,但是还是可以容忍的,因为不影响业务。

二是,是把存活的对象错误地标记成了死亡,那问题就大了,程序都没有办法正常执行了,所以 CMS 设计了重新标记这个阶段,用来修正并发标记期间因为用户限制继续执行而导致标记发生变动的那些对象的标记。

那么一般来说啊,重新标记所花费的时间会比初始标记花费的时间要长一些,但是比并发标记的时间会比初始标记花费的时间要长一些。但是也不是绝对的,主要还是看业务场景。另外,重新标记是存在 Stop The World 的。

第六阶段,再之后,CMS 又到了并发清理阶段,也有的书上翻译成并发清除,这个阶段会基于标记结果清除掉前面标记出来的垃圾,这个阶段也是并发执行的,没有停顿。

直接清楚对象是会存在内存碎片的,对吧?那么为什么 CMS 不整理一下对象呢?这是因为并发清除阶段它是并发执行的,如果整理对象的话是要移动对象的位置的,我们很难在并发状态下,一堆的线程在运行我们的业务,一堆的线程在做垃圾回收,回收的同时还要移动对象,然后移动对象位置的同时还要保证应用程序运行不出问题,而且实现起来非常难。所以采用并发清除,而不是并发整理。

最后阶段,最后一个阶段是并发重置,并发重置用来清理清理本次 CMS 的上下文信息,然后为下一次垃圾回收做准备。

下面来分析一下 CMS 收集器的特点:

CMS 的优点:一是, Stop The World 的时间比较短,从上图我们可以看出来,只有初始标记以及重新标记这两个阶段存在 Stop The World,其他的阶段都是并发执行的。

二是,CMS 大多数过程都是并发执行的。

CMS 的缺点有哪些呢?我们一起来看一下:

一是,CMS 对 CPU 资源是比较敏感的,在并发执行的那几个阶段,虽然不会导致 Stop The World,用户线程不会停顿,但是由于垃圾收集线程也会占用一部分 CPU 资源,所以会影响到应用程序的执行效率,导致吞吐量的降低。因为你想,有一堆的线程在做垃圾回收,同时还有一堆的线程在做业务。那就可能会存在业务线程和垃圾回收线程去争抢 CPU 时间片的情况,导致你的业务线程执行效率下降。

二是,CMS 没有办法处理浮动垃圾,由于 CMS 的并发清除阶段,用户线程还在运行,所以自然会有新的垃圾产生,那这部分垃圾就叫做浮动垃圾。CMS 没有办法在这一次收集就清理掉这些垃圾,要到下一次才能清理掉。

三是,CMS 不能等到老年代几乎满了才开始收集。这是因为在垃圾收集阶段,用户现在也在运行,那要运行就要去申请内存,于是我们必须预留足够的内存给用户线程去使用。要是 CMS 在运行期间预留的内存不能满足应用程序的需要,就会出现一次 Concurrent Mode Failure 这样的异常。这个时候就会导致虚拟机使用 Serial Old 作为后备去收集老年代的垃圾,这就是前面讲 Serial Old 的时候,所谓的 CMS 收集器出现故障的时候,也会使用 Serial Old 作为后备的场景。而一旦使用 Serial Old 的作为后备的话,Stop The World 的时间往往又会比较长了。因此在实际项目中,一定要预留好足够的内存,你可以使用这个参数:CMSInitiatingOccupancyFraction 去配置老年代的使用率达到多少的时候就触发垃圾收集,默认阈值是 68%。

另外 CMS 还存在内存碎片的问题,这个很好理解,因为 CMS 是基于标记清-除算法去实现的,所以会导致内存碎片的产生,这也是 CMS 最被人诟病的地方。当然了,你也可以使用这个参数:UseCMSCompactAtFullCollection 去设置,在完成 Full GC 之后进行内存整理,默认是开启的,也可以使用这个参数:CMSFullGCsBeforeCompaction 去指定每发生 Full GC 几次之后就做一下内存整理,默认阈值是 0。

那么前面我们说过,很多情况下, Major GC 和 Full GC 谈的是一件事情,对吧?但是对于 CMS 来说,Major GC 和 Full GC 不是一回事。CMS 是作用在老年代的垃圾回收,并不是 Full GC。

下面来看一下 CMS 收集器的适用场景:

如果你希望你的系统停顿时间要比较短,响应速度要比较的快,那么就可以考虑使用 CMS。那么一般来说,对于运行在服务器上的各种应用程序,比如一些 Web 应用,使用 CMS 收集器是比较合适的。

最后考虑到 CMS 比较复杂,简单小结一下。我们知道完整的 CMS 收集器总共分成了七个阶段:第一段段是初始标记,第二阶段是并发标记,第三阶段是并发预清理,第四阶段是并发可终止的预清理阶段,第五阶段是重新标记,第六阶段是并发清理,第七阶段是并发重置。其中三和四两个阶段不一定会执行,而且市面上很多文章甚至是直接略过的,因此对于应付面试的话,你只要记得一、二、五、六以及七这五个阶段就足以。不过要想真正理解 CMS,并且能够定位 CMS 垃圾收集器相关的问题,那么这七个阶段还是需要了解的。

©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 224,861评论 6 522
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 96,263评论 3 402
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 172,033评论 0 366
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 60,999评论 1 300
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 70,000评论 6 400
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 53,483评论 1 314
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 41,850评论 3 428
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 40,827评论 0 279
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 47,366评论 1 324
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 39,404评论 3 346
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 41,525评论 1 355
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 37,130评论 5 351
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 42,853评论 3 338
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 33,293评论 0 25
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 34,426评论 1 276
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 50,082评论 3 381
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 46,590评论 2 366

推荐阅读更多精彩内容