面试官看了我以前的文章对我说:你回去等通知吧!

这是why技术的第37篇原创文章web

老规矩,先聊聊生活,上面这张图片是我周一拍的。面试

周一夜下班后发现公司楼下推着三轮车卖花的阿姨又开始卖花了。整个路口只有她一我的在作生意,整条路上也没有几个行人,你们都低着头匆匆走着,繁花中带着点忧伤。并发

因而,我去买了一把白玫瑰。jvm

上周日把《霍乱时期的爱情》看完了,就恰好当道具拍了上面的照片。整体来讲我不喜欢这种纵情声色的故事,更不喜欢那个看起来堂而皇之的理由∶“我一辈子有622个情人,可是我只爱过你”。虽然它真的是穷极了爱情的全部可能性,可是它不够真实。编辑器

相比之下我以为钱钟书先生写的《围城》∶“我说的让她三分,不是三分流水七分尘的三分,而是天下明月只有三分的三分。”这样打打闹闹的爱情更加真实。post

再看杨绛先生的《咱们仨》,书的最后她说∶“世间好物不坚牢,彩云易散琉璃脆”。这才是爱情,这才是真实的生活。学习

好了,说回文章。spa

对不起,我错了。

前面发的这两篇文章:线程

《面试官:你说你熟悉jvm?那你讲一下并发的可达性分析》3d

《面试官:G1回收器怎么知道你是何时的垃圾?》

里面有一些没有说清楚的地方,又有不少读者来问,因此我以为须要补充说明一下

更重要的是,通过高手指点,其中还有一些描述错误的地方,我也须要进行勘误

若是真的是面试题,可能面试官就会对我说:好了,咱们今天就先到这里。你回去等通知吧。

若是你没看过我刚刚说的两篇文章,我建议你不要看这篇,由于一看就得看三篇,若是里面的衍生知识点你还想完全弄明白,一个下午就过去了......(固然,你看了后收获确定仍是有的。)

若是你看了我以前的两篇文章,我求求你必定看看这篇,补充、更正一下答案,等面试官真的问起细节来,也不怕......

好了,在阅读本文以前,我假设你已经读过我前面说的两篇优质、幽默、有料的文章了。

并发的可达性分析-勘误

以前发布了这篇文章《面试官:你说你熟悉jvm?那你讲一下并发的可达性分析》,对于文中这一部份内容中的动图,有不少朋友给我说看不懂:

我把这个动图拿出来:

首先,须要说明的是,我如今也看不懂这个动图了。(画错了就是画错了,还强行找个理由)。

接下来,忘记这个动图,咱们从新分析一波原始快照方案(如下简称SATB,Snapshot At The Beginning)。

首先,咱们看初始标记阶段(即根节点枚举)完成后,刚刚进入并发标记阶段,GC 线程开始扫描时的对象图:

在上面这张图里,当GC Roots肯定后,对象图就已经肯定了。SATB扫描的时候基于已经肯定的对象图(快照版的对象图)扫描,也就是说扫描过程当中上面的快照图的引用关系是不会发生变化的,可是真实的对象图是会发生变化的。

举个例子:就相似于你在操场上拍了一张照片,你数照片里面的人数,照片是不会发生变化,人数一直都是这么多,可是真实的操场上的人是在时刻变化的。

因此,在对象图肯定的一刻,正常扫描完成后,对象图变成了下面这样:

好了,面前的铺垫完成了。

咱们这里须要演示的是“对象消失”状况。

首先,咱们先肯定一下上面展现的对象图,在并发标记阶段必然有一个时刻的对象图是这样的:

咱们基于这个时刻的这个对象图去讨论“对象消失”的问题。

还得记得"对象消失"必须同时知足的两个条件吗?(这两个条件是摘抄自《深刻理解Java虚拟机(第3版)》P.89)

条件一:赋值器插入了一条或者多条从黑色对象到白色对象的新引用。

条件二:赋值器删除了所有从灰色对象到该白色对象的直接或间接引用。

咱们再仔细的读一遍第二个条件,你会发现,它说的是**“该白色对象”。这个“该白色对象”指的是条件一里面的白色对象。**

因此,咱们有理由相信:条件一和条件二是有前后顺序的,即必须是赋值器插入了一条或者多条从黑色对象到白色对象的新引用,而后赋值器又删除了所有从灰色对象到该白色对象的直接或间接引用。在这样的状况下,才会出现“对象消失”的状况。

通过高人指点,咱们还能够进行反证法,以下:

咱们假设灰色对象到白色对象的引用先删除了,即先触发了条件二。那么对应的这个时刻真实的对象图将变成下面的样子:

(注意我这里强调的是真实的对象图,而不是快照的对象图。再次重申:快照的对象图在扫描开始的时候就肯定了,扫描过程当中是不会变化的。)

那么,白色对象9是处于游离态的,从根节点没有任何引用链相连,用图论的话来讲就是从 GC Root 到对象9不可达,则证实此对象是不可能再被使用的。所以用户线程不可能把黑色对象5指向游离态的白色对象9,你写不出这样的代码来。

若是说上面的图你一眼没看出来,那么请看下面这图,是否是恍然大悟:

黑色对象5不能指向白色对象9,那么第一条规则就知足不了了。

因此,综上咱们能够得出:条件一和条件二是有前后顺序的。

那么咱们根据条件一继续作图以下:

条件一是赋值器插入了一条或者多条从黑色对象到白色对象的新引用。

在上面这个图的场景中,就是 GC 线程在工做的同时,赋值器插入了一条黑色对象5到白色对象9之间的新引用。(用红色线条以示区分)

在这个时刻,因为灰色对象6指向白色对象9,因此黑色对象5能够指向白色对象9,想想咱们前面的证实,只要有引用链,黑色对象就能够到达白色对象。

这个时候仅仅知足了条件一,对象还没消失。

接下来就是条件二的图,STAB破坏的就是条件二

条件二是赋值器删除了所有从灰色对象到该白色对象的直接或间接引用

在上面这个图的场景中,就是赋值器删除了灰色对象6到白色对象9的直接引用。

这个时候白色对象9就是“消失的对象”了,由于黑色的对象5是不会被再次扫描的。

须要注意的是,赋值器能够理解为用户线程,因为在并发标记阶段,用户线程和 GC 线程在同时运行,因此须要出现上面的图,还有一个前置条件就是:

用户线程删除对象6到对象9之间的引用,要先于 GC 线程扫描到对象6,把对象6变成灰色的操做。由于只有这样,GC 线程处理到对象6的时候,才有对应的写屏障记录。

若是在 GC 线程已经扫描过对象6,即对象6已是黑色的状况下(这个时候对象9,不是黑色就是灰色,不多是白色),用户线程再去删除对象6到对象9之间的引用,GC 线程是不须要处理的,由于对象9已是非白了,它在本轮中一定会活下来。

这里我引用R大的描述:

https://hllvm-group.iteye.com/group/topic/44381?page=2

由于删除操做会触发 pre-write barrier,把每次引用关系变化时旧的引用值记下来,只有这样,等 GC 线程到达某一个对象时,这个对象的全部引用类型字段的变化全都有记录在案,就不会漏掉任何在快照图里活的对象。固然,极可能有对象在快照中是活的,但随着并发 GC 的进行它可能原本已经死了,但 SATB 仍是会让它活过此次 GC,变成了浮动垃圾。

SATB 在写屏障里,把旧的引用所指向的对象都变成非白的(已经黑灰就不用管,仍是白的就变成灰的)。

这样作的实际效果是:若是一个灰对象的字段本来指向一个白对象,但在concurrent marker能扫描到这个字段以前,这个字段被赋上了别的值(例如说null),那么这个字段跟白对象之间的关联就被切断了。SATB write barrier保证在这种切断发生以前就把字段本来引用的对象变灰,从而杜绝了上述条件二的发生。

其中:“把旧的引用所指向的对象都变成非白的。”在咱们这个场景下含义以下:

旧的引用指的是:灰色对象6到白色对象9之间的引用。

所指向的对象指的是:白色对象9。

都变成非白的:指的是白色对象9变成了灰色。

因此,在两个条件顺序触发、对象图扫描完成后会变成下面的样子:

并发扫描结束以后,再以灰色对象9为根(把它做为根,天然会变成黑色),从新扫描一次,因此最终的对象图变成了这样:

有的小伙伴就会问了:若是在标记过程当中,用户线程并无把对象5指向对象9的操做,仅仅是发生了删除对象6到对象9之间引用的操做,那么这个对象图是什么样子呢?

就是下面这个样子,你应该能够想象出来:

对象9仍是黑色,只是它变成了浮动垃圾,逃过了本次回收而已。并不影响程序运行。

接下来,让上面的图动起来,而且我把图片之间的切换顺序放慢。你再本身细品品:

因此,上面的所有描述,才是一次我认为正确的,展现SATB方案是如何解决“对象消失”问题的过程。

以前《面试官:你说你熟悉jvm?那你讲一下并发的可达性分析》中对于这一部分的描述过于简单,且存在错误,给你们道歉,并特以此文进行修正。

你是何时的垃圾-勘误

在《G1回收器:我怎么知道你是何时的垃圾?》这篇文章中有一句描述是这样的:

“GC Roots 能直接关联到的对象:就是一个 Region 已经使用过的部分,因此在 bottom 与 top 之间。”这句话是错误的。

实际上,经过文章后面的描述你也能发现。GC Roots 能直接关联到的对象集合应该“小于” Region 已经使用过的部分,对象图递归完以后,全部对象总和,才等于Region已经使用过的部分。

经过文章中后半部分的这个图片也能够直观的发现, bottom 到 top 之间是一个 Region 已经使用的部分。可是这一部分中,只有 bottom 到 NextTAMS 之间的对象才是 GC Roots 能直接关联到的对象,这部分对象并非一个 Region 已经使用过的部分。

你是何时的垃圾-补充说明

关于《G1回收器:我怎么知道你是何时的垃圾?》这篇文章,还有两个须要补充说明的地方。

有的读者问说:文章中没有讨论回收的内容,每次清理不会真正回收,那是否是多轮标记后才发生一次回收呢?

一。

首先,文章中确实没有讨论回收相关的内容。我在前面部分也写了,把G1回收切分为两大部分:

1.Global Concurrent Marking:全局并发标记。

2.Evacuation Pauses:该阶段是负责把一部分Region里的活对象拷贝到空Region里面去,而后回收本来的Region空间。

只要清楚了全局并发标记阶段,就能够解答文中抛出的这个问题:

因此我只说明了全局并发标记阶段。

若是想要了解回收阶段的事,能够去看看R大的回答,强烈建议你看完本文,点个赞后,打开下面的连接,反复阅读几遍:

https://hllvm-group.iteye.com/group/topic/44381

其次,“每次清理不会真正回收,那是否是多轮标记后才发生一次回收呢?”

这句话,多是我在文章强调了清理阶段不拷贝任何对象,再加上没有描述回收阶段,致使读者有点懵了吧。

一次全局并发标记完成后,紧接着一次回收的过程。

只是G1收集器之因此能创建可预测的停顿时间模型(-XX:MaxGCPauseMillis指定,默认值为200毫秒),是由于它将 Region 做为单次回收的最小单元,即每次收集到的内存空间都是 Region 大小的整数倍,这样就能够有计划地避免在整个Java堆中进行全区域的垃圾回收。

更具体一点的作法就是每一个 Region 里面堆积的垃圾都有一个“价值”(价值即回收所得到的空间大小以及回收所须要的时间的经验值)。而这些“价值”,是维护在一个优先级列表中的,G1收集器都是知道的。

因此回收阶段会优先处理回收价值最大的那些 Region。所以,一次回收的过程并不会回收全部的 Region。

二。

这里也就解释了读者提出的另一个问题:若是每次标记完都会回收整理,那为何红框所在的区间与上一次标记以后相同,好像没有被整理同样,整理以后不是应该不留下内存空隙吗?

我以为一个合理的解释,就是我上面说的:这个 Region 的价值不够,因此它本次没有被回收。随着时间的推移,它里面堆积的垃圾愈来愈多,“价值”就愈来愈高,老是会被回收的。

还有读者问:看了并发标记的过程,有个疑问 prevBitmap 的做用是什么? 由于感受每次都是从头开始扫描,没看到它的做用。

这个问题,能够从这张图片入手解答:

这个 E 是 Remark 阶段,能够看到,在这个阶段,其实 PrevBitmap 是派上用场了。

前面刚刚说了,这个 Region 因为“价值”不够,它逃过了上次垃圾回收,因此待到下次垃圾回收的时候,就是 prevBitmap 的用武之地了,它里面记录的地址对应的区间就不须要再次标记了,由于这些地址对应的对象就已是垃圾了。

咱们能够假设 E 表明的是第 n 轮回收的过程的Remark阶段。那么 PrevBitmap 就是第 n-1 轮的标记结果。

以前的文章说了:一个 previous Bitmap 记录的是上一轮 Concurrent Marking 后的对象标记状态,由于上一轮已经完成(上一轮就是第n-1轮),因此这个bitmap的信息能够直接使用。

能够直接使用的意思就是前面说的:它里面记录的地址对应的区间就不须要再次标记了,由于这些地址对应的对象就已是垃圾了。

到 F 图里面,能够看到,当前的 F 图是清理阶段已经完成的状态了:

判断标准有二:

1.和 E 图相比PrevBitmap 和 NextBitmap 已经交换了位置。

2.PrevBitmap 里面对应的地址的空间已经被标记为浅灰色了。

这个时候已经完成标记,PrevBitmap 又变成了第n-1次标记的结果。

你是什么垃圾-怼人

由于以前的文章已经发布了,因此我须要修改一下对应的内容。提醒后面的读者,若是看到了文章,须要注意这些地方描述的有问题。

可是我在查找我文章的过程当中发现了一些让我很郁闷的事情,以前的文章,大都被剽窃了,我也见怪不怪,有时间就顺手举报一下了。

最过度的是下面这个:

这是一个百家号帐号,一字不差的抄我文章,还本身标注为“原创”?

我去写了个评论:

他还不敢把评论放出来。

还有下面这个,你可长点心吧。你配的这张图片,我却是想在家拍,可是我拍不出来呀:

这样的状况还有不少。说到底,就仍是版权意识的问题。

版权问题,我以前在《订阅号作了77天,我挣了487.52元》这篇文章里面聊过:

个人号不会传播任何盗版资源,之前如此,如今如此,之后也会如此。

不作恶,就是最大的善。与君共勉。

因此我在此郑重声明,若是未经许可转载个人文章,必须标明原文地址,且保留文末公众号二维码,不然我必定见一个举报一个。

我先举报你涉黄,引发工做人员的注意,再举报你抄袭,让工做人员惩罚你。

气死我了。

最后说一句(求关注)

经过这件事我也再次感受到了,看网上的野生文章(好比个人),要持有谨慎、怀疑、学习的态度。

才疏学浅,不免会有纰漏,若是你发现了错误的地方,还请你留言给我指出来,我对其加以修改。(我每篇技术文章都有这句话,我是认真的说的。)

感谢您的阅读,我坚持原创,十分欢迎并感谢您的关注。

我是why技术,一个不是大佬,可是喜欢分享,又暖又有料的四川好男人。

以上。

欢迎关注公众号【why技术】,坚持输出原创。分享技术、品味生活,愿你我共同进步。

相关文章
相关标签/搜索