00:00
那针对啊,咱们刚才讲完的这个工作原理啊,咱们下边呢,进行一些分析啊,进一些分析,首先的话呢,我们关注到啊,这里边提到了一共是这样的四个环节,对吧?诶把它呢,我们再定一下啊放到这儿,那么在这个四个环节当中啊,我们说这个第一个环节叫初始标记和第三个叫重新标记,这两个环节呢,他们是需要这个stop the world这个机制的,哎,这个stop the world呢,就是我们也称为呢,叫做独战式对吧?哎,叫做这个独战式机制,但是呢,诶比较可喜的是呢,这两个环节他们花的时间啊,并不会特别长。啊,或者换句话说也就非常的短啊,呃,那这呢,我们想强调就是目前呢,所有的垃圾回收器要想完全不需要stop the word是不可能的,包括呢,我们说这个g e j first也好,还有我们最后要提的这个ZJC,或者这个神do jc也好,他们呢,都只能说呢,尽可能的去缩短这个暂停时间,完全没有这是不可能的啊,这个大家注意一下这个问题。下一个的话呢,说由于最耗时的这个操作呢,是我们这个第二个环节叫做并发标记,以及呢,第四个环节叫做并发清理,那么这两个环节呢,虽然最耗时,但是的话呢,他们都是可以并发执行的,对吧,跟我们这个用户限制呢,可以并发执行,所以说整体上呢,我们这个回收啊,就是一个叫低停顿的。
01:13
诶大家呢,先去理解说为什么说这个CMS呢,垃圾回收器呢,成为一个叫低延迟的,大家呢,就可以通过我们这样的一个工作原理,或者它的一个实现过程,诶大家呢,去给呃一个解释啊,你首先自己得清楚,然后面试的时候呢,你也可以给他讲出来,对吧?诶这是这个事情,好,那下边我们来看这个事儿说啊由于这个垃圾收集阶段呢,呃,这个用户线上是没有中断的,哎,就是我们标记并发标记也好,还有我们这个并发清理也好,是吧,这呢是用户线上是没有中断的,所以呢,在这个CMS呢,回收过程当中还应该确保啊应用程序的这个用户线上呢,有足够的内存呢,可以使用。诶,足够的这个内存可以使用,哎,就相当于是呢,咱们在这个并发标记的这个过程当中,咱们这个用户现场还在不断的去执行它,不断的执行的话呢,是不是就有可能是使用更多的内存啊,哎,那大家想一下,如果像以前的我们那个垃圾回收器说这个用户限量正执行着呢,然后突然内存不够了,也就是说呢,不够我们再去分配新的对象了,EIG呢,就是你已经接近100%了,对吧,这个时候呢,我们卡一停这个,呃,用户线程直接呢,就STW了,我们这时候呢,开始回收垃圾了。
02:19
这时候没毛病对吧,但是你现你看对于我们这个CMS来讲的话呢,因为呢,在我们回收的过程当中,用户线程还在执行,花的时间还挺长,所以呢,这个时候咱们就不能够等到是不是内存不够的时候呢,咱们再去进行啊垃圾回收了。因为要那样的话呢,你想这个用户现在一执行是不是很有正,我现在正回收着呢,然后你这块呢,又一执行是不是很容易的就内存溢出了。直接就挂了是吧?诶所以不可以啊,诶言外之意呢,就是说我们需要呢,这个诶得这样啊,当堆内存使用率达到一定的阈值的时候啊,一会儿呢,咱们看这个阈值的一个设置情况啊,当这个堆内存的使用率啊达到一定阈值的时候呢,咱们就开始进行垃圾的一个回收。
03:02
哎,就要开始回收了,确保呢,这个应用程序呢,在这个CMS工作过程当中,有足够的这个空间啊,去支持啊应用程序的这个运行。这个概念应该很好理解对吧?那那比如说达到这个阈值的时候呢,诶我们这块呢,就诶开始进行这个CMS垃圾回收了,那如果说这个时候的用户线程这个产生垃圾的速度非常的快,远超于我们垃圾回收的这个速度的话呢,是不是就有可能会出现下边这个问题啊。我们称为呢,叫con mode failure,就是我们并发出现了一个错误啊,就失败了。啊,当然这个呢,还有可能是我们CMS呢,运营过程当中预留的内存发现不够是吧,哎,不够呢,这是一个结果了,那这个不够呢,有可能是因为我们用户线程呢,执行的速度远超于这个垃圾回收的线程啊那时候不够了,不够了,那这时候该怎么着了,那你停一停吧,是吧,这时候用户线程你别走了,你再走咱再就溢出了是吧,我现在已经开始回收了啊,你你别走了,那就意味着咱们当前这个CMS呢就停下来了。
04:00
那CMS1停下来之后呢,那怎么办啊,这个时候我们就要启动这个预备方案。诶,我们要临时的去启动啊,叫zero old的垃圾回收器,进行老年代的一个垃圾回收。啊,但是这时候你能够想象到,本来呢,是一个,诶是不是可以多线程这种执行的是吧?诶并发的一个模式,然后现在呢,突然换成了一个,诶需要呢,Stop word时间很长的一个模式,而且还是一个串型的哈,很崩溃是吧,很崩溃没有办法啊,但实际上你这个失败了呢,而且呢,这个C的话呢,我们说采用的是不是叫标记压缩算法。哎,标记压缩算法啊comp是吧,所以这块呢,它还会对内存呢,进行一个碎片的一个整理啊,这方面倒是还是挺好是吧?好,那我们接着往下看啊,说这个CMS呢,它采用的叫标记清除算法,诶这个呢,就是咱们说的这个内存碎片的问题啊,就是任何事物都有利有弊嘛,对吧,这呢就我们在提他这个弊端,因为呢,你使用的叫标记清除算法,那就意味着我们这个内存中是不是会产生这个碎片啊,哎,你比如说我们这个内存中,我这个一标记啊,这个打叉呢,这就是我们这个垃圾了,然后呢,回收完以后,这个呢,都是回收掉了。
05:05
那那剩下的一个空间呢,你看它这对应的是不是就是一些呃,散状的这个区域了是吧?比如这个白的呢,是我们这个占用的,然后呢,你把它回流掉之后呢,诶这些呢,都是我们可以下次去使用的,但是呢,这个空间呢,就是碎片化的。那碎片化的这个内存,我们接下来如何再去分配新的对象啊,咱们前面都讲过了,是不是只能使用这个叫空闲列表的方式啊,哎,指针碰撞呢,针对的是这个内存比较规整的是吧?就是哎清除标记压缩的那个算法,咱们才能使用这个叫智能碰撞啊,OK啊,这个呢,大家能够去理解行,那么呢,基于刚才我们提到这个说标记清除呢,既然有内存碎片,那干什么我们这个CMS不用这个叫标记压缩算法呢?哎,我把这个答案呢挡一挡,大家想一想。你看你能不能理解清楚。诶标记清除说过了是吧,诶它呢会造成这些内存碎片,那为什么我们不用一下叫标记压缩呢。不压缩不挺好吗?内存碎片就解决了呀。
06:03
为什么不行呢?诶,其实这块呢,大家你主要就看这个过程了。哎,你看这个过程。你看我们这个呢,是不是叫并发呀。并发呢是什么意思啊,就是说诶这个我一边呢,垃圾清除,用户限制呢,还一边去执行,你想想,如果这个时候我们要使用的叫标记压缩算法,你想想,那我们是不是要对内存呢,进行一个重新的一个整合呀,比如说这是一个对象,这个对象这个对象,这个对象我们要压缩的话呢,你是不是这个时候要把这个对象呢,是不是要移过来,诶往一块儿呢去移,让他们呢紧密排列对吧?那你想想这个时候用户线上它可是还在执行啊,在执行的过程当中,你把这个对象的地址给修改了。这课是不是很崩溃啊?啊,这个要注意啊,诶所以呢,这个答案呢,就是说我们因为呢,要保证这个用户线上呢还能够继续的执行,所以你不能够改变这个他所使用的那个对象的地址。啊,因为你是并发的嘛,既然并发,所以只能够使用这个叫sweep。那如果就想使用这个Mac comp怎么办啊,那没办法,这时候你必须得让这个用户现场得停下来,你停一下啊,然后你现在你使用这个对象呢,我给你把位置给你改了,然后呢,你再起来,哎,所以呢,你要是用哎标记压缩算法一定得是stop the word。
07:16
对吧,诶这是stop the word,但是咱们是不是希望呢低延迟啊,诶所以呢,只能够使用叫诶标记清除算法。啊,应该能解释清楚啊好,那么这里边儿呢,咱们系统呢,总结一下说这个CMS呢,它这个优点是什么呀?啊优点的话呢,就是首先呢提到了它是一个并发操作的啊第二个环节,第四个环节是并发的啊那并发呢,诶那么相应的这个好处呢,就是说我们可以用户线程呢,可以同时去执行它呢,不算是stop the word了,那对于我们这个第一个环节和第三个环节来讲呢,来讲呢,我们这个stop the word这个时间呢,又非常短,所以它是一个叫低延迟的。啊,就非常好理解是吧,就针对咱们这个1324是吧,这两个环节呢,去说明就行啊。下边啊,咱们重点呢,来说一下这个CMS的一个弊端。
08:03
哎,它这个弊端,那就是也正因为呢,它有这样的一些弊端,实际上呢,也导致了咱们后边啊,确实呢,就不想再用这个诶CMS了。不想再用它了,或者说呢,我们又想着办法呢,去研发新的垃圾回收器,是不是这个g first就出现了?哎,就这样一个道理啊行,那首先的话呢,我们来看一下这个第一个啊说呢,它会产生内存碎片,咱们刚才已经说过了,导致呢,并发清除以后呢,用户线程呢,可用的这个空间呢,会不足,在无法呃这个在无法分配这个大对象的情况下呢,不得不提前触发一次叫forc。哎,能理解吧。对吧,哎,我们说这个GC的话呢,它不能够等待这个内存啊耗尽的时候呢,才采取JC,刚才呢,我们说提到的有一个阈值。对吧,它有个阈值啊,另外一方面呢,你本身还有碎片啊,你本身有碎片呢,就导致你这个内存空间呢就不太规整,有可能我们这个老年代呢,是不是这时候呢,空间其实还空着很多,但是呢,就由于你这个碎片化呢很严重,来了一个大对象,这时候呢,发现老年代呢还空很多,比例上空很多,但是呢,又没有一个地儿能放得下。
09:09
这就麻烦了,是不是导致我们提前呢,是不是就会触发这个叫forc了,哎,这就很尴尬了是吧?哎,Forc的话呢,是不是又是一个停顿啊。哎,这要注意一下是吧,好第二个话呢,说这个CMS呢,这个垃圾收集器呢,对CPU的资源啊,是非常敏感的。啊,对CPU的资源非常敏感,在并发阶段呢,它虽然不会导致用户停顿啊,并发阶段不会导致用户,但是呢,会因为占用了一部分这个线程而导致呢,应用程序变慢,吞吐量降低,能理解吗?你看这儿啊,我这个图章呢,这是一个概图啊,就是大概的一个情况,我这呢是标志了有呃标识了有四条,哎,你可以理解成是四个线程,或者有四个CPU也行,咱们呢,其中分配了一个是不是用于这个叫哎垃圾回收是吧,那相当于呢,本身四个用户线程要都执行肯定效率更高,但是现在你分出一部分呢,用于垃圾回收,所以导致呢,咱们这个吞吐量呢,是不是就有所降低啊。对吧,哎,就这样一个场景,那么具体的话呢,我们说这个,呃,CMS呢,设置这个CPU它到底应该是多少呢?咱们后边呢,有专门来设置来设置,你看这啊,Parallel Ms service,就我们来设置一下这个并发的这个,呃,并行的这个,其实就并行同时执行的这个,哎,垃圾回收器的这个线程是多少,那这块有一个公式。
10:21
那这有个公式,这个呢,实际上呢,你也可以理解成就是我们这个,因为默认的这个parallel j c th是不是就是我们CPU的一个个数啊。哎,你就可以理解成是CPU这个数加上三除以四,那举个例子,比如说我们这个CPU呢,就是有四个CPU,四个CPU加上三是七,七除以四啊这个结果呢一点多,所以我们会有一个,哎就是如果你要是四个CPU呢,会有一个呢,是不是用于垃圾回收是吧?哎,那我要是五呢,哎五加三是八,哎那就是有俩,那你相当于呢,你看是不是有1/4,四个CPU的时候有1/4呢,是不是进行垃圾回收,五个的话呢,相当于有2/5,哎用于这个垃圾回收,这有40%了,那你想想这时候呢,呃,如果呢,有五个CPU,我们完全用于用户线程,跟现在呢,你有60%用于用户线程相比,那很显然咱们这个,呃使用CMS这个方式呢,确实呢是低延迟的,但是呢,是不是导致我们这个吞吐量呢,实际上是降低了,因为你并发了嘛。
11:16
对吧,哎能理解啊好,这呢就是我们说的这个事情,然后下一个呢,说这个CMS呢,垃圾回收器,它无法处理浮动垃圾。这个呢,是咱们第一次听这个词,叫做浮动垃圾。什么叫浮动垃圾呢?那啥叫浮动垃圾呢?诶这个呢,注意咱们在这个重新标记这个环节啊,诶提到过一个事情说呢,呃,由于你这个并发标记环节呢,是用户线程和垃圾回收线程,呃这个都在执行,那我们这个呢,是是不是需要做一个叫修正是吧。哎,需要做一个这个修正,那修正什么呢?哎,就是修正了,咱们这个在并发标记这个环节啊,有一些之前没有办法确认这个是不是这个垃圾的一个情况啊,会做一些修改啊,就是你怀疑他是垃圾,但有可能他又不是,这个时候我们需要重新标记,把那些怀疑的呢,你确认一下他可能是垃圾,可能不是,不是的话呢,你就不能给人家去回收了。
12:08
对吧,哎,这个针对的就是怀疑的那些对象,但是呢,我们在这个,呃,就是并发标记的这个环节当中啊,咱们还有另外一部分的数据,那部分数据是啥呀,就是本身人家呢,一开始不是垃圾。但是呢,在这个用户现场执行过程当中,它变成垃圾了。我再说一遍啊,在这个并发标记环节,呃,在这个重新标记环节,咱们修正的是什么呀?修正是原来怀疑是垃圾,但是呢,我们这时候需要确认一下他是不是真的是垃圾,就怀疑是垃圾的那些对象啊,但是呢,我们还有一部分对象呢,是本身它不是垃圾,在并发标记这个时候,它本身不是垃圾,但是呢,诶,那这个就就是相当于是这个初始标记的时候,他也不是垃圾,在并发标记你执行的过程当中呢,它变成了这个垃圾了。哎,这一部分数据咱们呢,在当前这个重新标记之后呢,是不包含他们的,所以我们清理当中呢,也没有这些数据。
13:00
啊,就这里边写的,在并发标记阶段,如果产生新的这个垃圾对象了,CMS呢,就没办法对这些垃圾呢进行标记了。啊,没办法对这些这个垃圾进行标记了,那最终呢,会导致这些新产生的这个垃圾对象没有办法被及时的回收。啊,那么这些没有被及时回收的这个数据啊,咱们就称为呢,叫做诶浮动垃圾。叫做浮动垃圾啊,实际上呢,就是这个意思,你比如说我们这个是叫GC root是吧。诶GC诶如此行,然后这块呢,我们关联关联关联关联关联关联关联关联关联关联好那么能关联到的话,我们说呢,都认为呢不是垃圾了,那么没有关联到的那些,咱们是不是这块都已经清理掉了,那么在你这块并发标记的这个过程当中,有一些关联这个对象呢,突然他就不关联了这些数据啊,咱们是一开始不能够在第一次的这个过程当中清理掉了,你只能是第二次又进行这个CMS的时候呢,我们才会把它们,诶再去标记的时候,是吧,才能够把它们呢给清理掉,诶这呢就是叫哎浮动垃圾。
14:01
啊,这就叫做个浮动垃圾行,那么基于呢,咱们现在讲的这三个点啊,大家呢,去想这样一个场景啊,尤其是咱们这个所谓的叫碎片化的问题。啊,你你设身处地的现在想一想。啊,说这个碎片化的问题,我这样说啊,他呢,呃,随时相当于是给我们这个GMGM呢埋了一颗这个定时的炸弹。啊,怎么理解啊,你想想啊,说不定呢,咱们这个程序在执行过程当中啊,你实际上这个后台正在正常运行是吧,然后突然呢,来了一次这个业务的高峰啊,业务的高峰呢,有可能我们会出现一次这个forc。对吧,业务高峰以来,我们来一次这个for GC是吧,提前出发了,哎,那出发这个for GC的时候呢,我们这时候呢,又把这个呃CMS,诶前面提到的是不是把它呢,又当做是我们这个后备的一个方案是吧?而这个CMS呢,大家知道它又是我们讲的这个垃圾回收器当中呢,性能呢算是最差的一个了。我们做这个后台的话呢,或者跟用户交互,我们现在呢,都是这个性能都比较强,CPU呢也不不会说是单核的了,对吧,那么在这个时候呢,你既然启用了一个单线程的一个啊sir o的这样的一个垃圾回收器。
15:10
啊,是我们GM当中性能最差的一个,那它呢,有可能啊,停顿的是几秒钟,甚至说呢,呃,十几秒钟。那你在这一次业务高峰期来临的时候呢,让很多用户是不是都感觉到非常卡顿,那这个事儿的话呢,我们是很难接受的。哎,是很难接受的,所以这块呢,大家一定要注意一下啊,CMS呢有些弊端呢,是非常致命的啊,后边呢,我们就把这个CMS呢给替换掉了。啊,就是这个时候呢,我们为了达到这个低延迟啊,咱们牺牲的东西啊,还是比较多的啊,还是比较多的,所以呢,我们后边呢,是不是引入这个g first又来了一个新的一个思路啊,那就是基于这个分区算法,也是现在呢比较主流的一种啊设计方案。啊OK,行这呢,我们就先介绍到这儿啊。
我来说两句