关于java:稳了我准备了1个晚上的CMS垃圾收集器

38次阅读

共计 2631 个字符,预计需要花费 7 分钟才能阅读完成。

面试官 明天还是来聊聊 CMS 垃圾收集器呗?

候选者:嗯啊…

候选者:如果用 Seria 和 Parallel 系列的垃圾收集器:在垃圾回收的时,用户线程都会齐全进行,直至垃圾回收完结!

候选者:CMS 的全称:Concurrent Mark Sweep,翻译过去是「并发标记革除」

候选者:用 CMS 比照下面的垃圾收集器(Seria 和 Parallel 和 parNew):它最大的不同点就是「并发」:在 GC 线程工作的时候,用户线程「不会齐全进行」,用户线程在「局部场景下」与 GC 线程一起并发执行。

候选者:然而,要了解的是,无论是什么垃圾收集器,Stop The World 是肯定无奈防止的!

候选者:CMS 只是在「局部」的 GC 场景下能够让 GC 线程与用户线程并发执行

候选者:CMS 的设计指标是为了防止「老年代 GC」呈现「长时间」的卡顿(Stop The World)

面试官 那你分明 CMS 的工作流程吗?

候选者:只理解一点点,不能多了。

候选者:CMS 能够简略分为 5 个步骤:初始标记、并发标记、并发预清理、从新标记以及并发革除

候选者:从步骤就不难看出,CMS 次要是实现了「标记革除」垃圾回收算法

面试官:嗯…是的

候选者:我就从「初始标记」来开始吧

候选者:「初始标记」会标记 GCRoots「间接关联」的对象以及「年老代」指向「老年代」的对象

候选者:「初始标记」这个过程是会产生 Stop The World 的。但这个阶段的速度算是很快的,因为没有「向下追溯」(只标记一层)

候选者:在「初始标记」完了之后,就进入了「并发标记」阶段啦

候选者:「并发标记」这个过程是不会进行用户线程的(不会产生 Stop The World)。这一阶段次要是从 GC Roots 向下「追溯」,标记所有可达的对象。

候选者:「并发标记」在 GC 的角度而言,是比拟消耗工夫的(须要追溯)

候选者:「并发标记」这个阶段实现之后,就到了「并发预处理」阶段啦

候选者:「并发预处理」这个阶段次要想干的事件:心愿能缩小下一个阶段「从新标记」所耗费的工夫

候选者:因为下一个阶段「从新标记」是须要 Stop The World 的

面试官:嗯…

候选者:「并发标记」这个阶段因为用户线程是没有被挂起的,所以对象是有可能发生变化的

候选者:可能有些对象,从新生代降职到了老年代。可能有些对象,间接调配到了老年代(大对象)。可能老年代或者新生代的对象援用产生了变动…

面试官 那这个问题,怎么解决呢?

候选者:针对老年代的对象,其实还是能够借助类 card table 的存储(将老年代对象发生变化所对应的卡页标记为 dirty)

候选者:所以「并发预处理」这个阶段会扫描可能因为「并发标记」时导致老年代发生变化的对象,会再扫描一遍标记为 dirty 的卡页

面试官:嗯…

候选者:对于新生代的对象,咱们还是得遍历新生代来看看在「并发标记」过程中有没有对象援用了老年代..

候选者:不过 JVM 里给咱们提供了很多「参数」,有可能在这个过程中会触发一次 minor GC(触发了 minor GC 是意味着就能够更少地遍历新生代的对象)

候选者:「并发预处理」这个阶段阶段完结后,就到了「从新标记」阶段

候选者:「从新标记」阶段会 Stop The World,这个过程的进展工夫其实很大水平上取决于下面「并发预处理」阶段(能够发现,这是一个追赶的过程:一边在标记存活对象,一边用户线程在执行产生垃圾)

候选者:最初就是「并发革除」阶段,不会 Stop The World

候选者:一边用户线程在执行,一边 GC 线程在回收不可达的对象

候选者:这个过程,还是有可能用户线程在一直产生垃圾,但只能留到下一次 GC 进行解决了,产生的这些垃圾被叫做“浮动垃圾”

候选者:完了当前会重置 CMS 算法相干的外部数据,为下一次 GC 循环做筹备

面试官:嗯,CMS 的回收过程,我理解了

面试官 听下来,其实就是把垃圾回收的过程给”细分”了,而后在某些阶段能够不进行用户线程,一边回收垃圾,一边解决申请,来缩小每次垃圾回收时 Stop The World 的工夫

面试官:当然啦,两头也做了很多的优化(dirty card 标记、可能中途触发 minor gc 等等,在我了解下,这些应该都提供了 CMS 的相干参数配置)

面试官 不过,我看当初很多企业都在用 G1 了,那你感觉 CMS 有什么毛病呢?

候选者:1. 空间须要预留:CMS 垃圾收集器能够一边回收垃圾,一边解决用户线程,那须要在这个过程中保障有短缺的内存空间供用户应用。

候选者:如果 CMS 运行过程中预留的空间不够用了,会报错(Concurrent Mode Failure),这时会启动 Serial Old 垃圾收集器进行老年代的垃圾回收,会导致进展的工夫很长。

候选者:显然啦,空间预留多少,必定是有参数配置的

候选者:2. 内存碎片问题:CMS 实质上是实现了「标记革除算法」的收集器(从过程就能够看得出),这会意味着会产生内存碎片

候选者:因为碎片太多,又可能会导致内存空间有余所触发 full GC,CMS 个别会在触发 full GC 这个过程对碎片进行整顿

候选者:整顿波及到「挪动」/「标记」,那这个过程必定会 Stop The World 的,如果内存足够大(意味着可能装载的对象足够多),那这个过程卡顿也是须要肯定的工夫的。

面试官:嗯…

候选者:应用 CMS 的弊病如同就是一个死循环:

候选者:1. 内存碎片过多,导致空间利用率减低。

候选者:2. 空间自身就须要预留给用户线程应用,当初碎片内存又加剧了空间的问题,导致有可能垃圾收集器降级为 Serial Old,卡顿工夫更长。

候选者:3. 要解决内存碎片的问题(整顿),同样会卡顿

候选者:不过,技术实现就是一种 trade-off(衡量),不可能你把所有的事件都做得很完满

候选者:理解这个过程,是十分乏味的

面试官:那 G1 垃圾收集器你理解吗

候选者:只理解一点点,不能多了

候选者:不过,留到下次吧,先让你消化下,不然怕你顶不住了。

本文总结

  • CMS 垃圾回收器设计目标:为了防止「老年代 GC」呈现「长时间」的卡顿(Stop The World)
  • CMS 垃圾回收器回收过程:初始标记、并发标记、并发预处理、从新标记和并发革除。初始标记以及从新标记这两个阶段会 Stop The World
  • CMS 垃圾回收器的弊病:会产生内存碎片 && 须要空间预留:进展工夫是不可预知的

欢送关注我的微信公众号【Java3y】来聊聊 Java 面试,对线面试官系列继续更新中!

【对线面试官 - 挪动端】系列 一周两篇继续更新中!
【对线面试官 - 电脑端】系列 一周两篇继续更新中!

原创不易!!求三连!!

正文完
 0