当前位置: 主页 > CMS相关 > Zblog

小白学JVM系列-CMS(jvmq)

时间:2023-03-04 06:39:16 Zblog 我要投稿

发。

复习一下,并发是用户线程和GC线程一起执行GC最怕的是什么,停顿, Stop the world,现在好了,GC线程工作时,用户线程可以跟着一起执行但是整个GC过程无法做到一直不停顿,CMS能做的就是把停顿时间缩短,有过编程经验的人都知道,一般速度优化了,算法就变复杂了。

看看CMS的步骤就知道变得怎么复杂了?看下图

共四个阶段黑色的初始标记,时间很快他只是标记,GCroots能直接关联的对象并发标记,把直接关联的对象,tracing下去最终标记,Remark:修正,并发标记过程中因为用户线程而变动的那一部分对象的标记记录。

时间比并发标记短很多并发清除,真正的清除阶段,也是并发的,不影响用户线程整个CMS最耗时的是第二条并发标记 因为是并发,交替工作,会有新的垃圾,需要重新标记,最后清理也就是说第三步是对第二步特殊情况产生的垃圾的补充处理。

最后一步,并发清理会产生浮动垃圾标记清除会产生碎片,CMS只是加了并发,依然会有碎片复制才没有碎片面试的时候,有时候就问这样一个问题,什么情况会报错 Concurrent Mode Failure, 这个错误其实就是是cms时的错误,如果老年代的空间,无法容纳新生代转移来的那么上了年纪的对象,就会报这个错误。

这时 CMS 就知道自己的能力已经无法胜任目前的工作了JVM 早就为CMS找好了备胎,Serial Old,Serial Old 可以让老年代空间更大,但是代价也不小,性能很差,这个过程中,完全 Stop the world。

现在,我们先简单总结下 CMS的优缺点优点:两个过程都是并发工作,会降低停顿时间缺点,对cpu敏感,毕竟并发的程序都是争夺CPU的那么碎片问题,该怎么处理好呢?CMS调优详解 标记清除,标记分了三步走,最后才标好,清除。

只有第三步-重新标记是STW,前面两步都是为了STW的时间够短 复习下,这个图这个时序图,脑子里要有个印象Cms是标记清除算法,所以只有标记,清除如果第一次看CMS,肯定是一脸懵逼别灰心,我当初也是不是因为难,看不懂无非就是不熟悉,名词多。

多看几遍,你再看看还难不难,看了三遍,新名词就是旧词了,词都不默认,你再想想整体的思想,每次都会理解多一分CMS收集过程: 完全记不住:一句话标记存活的,清理未存活的 再进一步:并发标记,stw标记,清理未存活的。

再进一步:stw标记开头,并发标记,stw标记结尾,并发清理未存活的如果一次记不住,你可以按照上面的顺序一步一步来,学习嘛,本来就是一个熟练的过程,只要走在正确的道路上,有时候慢就是快如果你们的内容,都掌握了,才可以继续往下看。

如果你们的内容,都掌握了,才可以继续往下看。 如果你们的内容,都掌握了,才可以继续往下看。

为什么,我强调了三遍,因为前面的掌握好了,下面的内容才可能学的进去啊CMS 第一次把 GC的过程分成了四个步骤下面是对每个步骤的详细解释我们这里需要先讲述一个概念那就是 JVM 如何判断一个对象是正常的对象,还是垃圾对象呢?。

要知道对象可是有引用的关系,是不是说如果一个对象还被其他对象引用者,就是正常对象呢?对也不全对,为什么这么多大部分情况,对象被引用就是正常对象,但是也有种特殊的情况,两个对象 A 和 B,他俩互相引用,再没有第三者引用他俩,这时,他俩满足被引用,但是其实他俩是垃圾对象。

他俩就像悬浮空中的花一样,没有根这里引出了一个概念,根,也叫 GCRoot 如果一个对象,直接或者间接被 GCRoot引用,那么他就是正常对象从 GCRoot 出发,找出所有被它直接,间接引用的节点的过程就叫做 GCRoot 的可达性分析。

上面举例的两个对象 A 和 B 既然是垃圾对象, 说明 JVM 不承认他们是 GCRoot,那么都什么对象有幸成为 GCRoot 呢?当然是天选之人,哦不,是天选对象局部变量表中的对象方法区的类属性引用的对象。

方法区的常量引用的对象native 引用的对象看到了吧,都是一些比较特殊对象,他们引用的对象,都是正用着的,有用的,不能随意清除的对象好了,我们重新来看看四个步骤初始标记 这一步标记的节点就是 GCRoot 节点,而 GCRoot 节点数量是有限的,所以速度很快。

具体又分为两种标记old中的所有GCRoot标记old区中被Young区引用的对象 (CMS是 old区算法,标记的当然都是old区的对象,young区不管 但是如果一个 old 区对象还在被 CMS 不管理的 young 区引用,这个对象也不能被回收,它算是特殊的 GCRoot, 这句话需要慢慢品。

)并发标记 上一步标记了,所有 GCRoot 节点,这一步就是顺着所有的 GCRoot 节点,把每个根节点的树,遍历一遍因为只是顺着 GCRoot 继续往下找,基本上不影响应用程序,所以这个过程,可以并发,GC和 应用程序,各干各的活。

注意,是基本不影响,不是完全不影响因为这个过程产生的新垃圾就没有办法了 因此,这个阶段出现的垃圾,没有被标记重新标记 并发标记,因为并发减少了停顿时间,但是也对应的付出了代价,就是一些异常情况,标记中产生的新垃圾没有标记。

还好,并发标记利用集合把变化的部分就保存下来了,它不处理,但是他保留了现场 重新标记呢,拿到这些变化,重新扫描一遍这时为了安全,就必须得 Stop the world 了并发清理 到了清理这一步,还是老规矩,清理意见标记位垃圾的对象,这时候就可以并发的,这一步产生的垃圾当然也是无法处理的。

所以如果到了这一步,如果空间不够用了,CMS 就会泛起抵抗,进入 Serial Old 模式上面提到的并发过程中的新垃圾,有个对应名词,叫做浮动垃圾到了这里,是不是感觉 CMS 的内容太多了,其实我可以很负责任的告诉你,还有很多内容没有细讲,比如预清理,比如记忆集的处理机制,比如一些参数的默认值。

东西很多,我们留着后续展开,知识要慢慢的学,慢就是快

猜你喜欢