面试官问我G1回收器怎么知道你是什么时候的垃圾? (1)

简介: 面试官问我G1回收器怎么知道你是什么时候的垃圾? (1)

上面的图片是我上周末在家拍的。以后的文章里面我的第一张配图都用自己随手拍下的照片吧。分享生活,分享技术,哈哈。


阳台上的花开了,成都的春天快来了,疫情也应该快要过去了吧。


最近在看《霍乱时期的爱情》,不知道为什么和《大话西游》联系了起来,所以你可以看到玻璃上的倒影,是我在看《大话西游》。


谁都曾经有过大闹天宫的梦想,爱上层楼的忧愁,但是早晚有一天,你也会像他转身之后一样,走在路上,像一条狗。


好了,说回文章


image.png


让你看看“浮动垃圾”


《面试官:你说你熟悉jvm?那你讲一下并发的可达性分析》这篇文章主要聊了 jvm 的可达性分析算法。


借助“三色标记”大法分析了垃圾回收线程扫描的过程中,用户线程同时执行修改引用关系的操作时,可能会出现的“对象消失”问题,以及其对应的两种解决方案

增量更新和原始快照。


在文章中我写道:对象关系图的变化会导致出现两种情况一是“浮动垃圾”,二是“对象消失”。大概率的情况下面试官更加关心第二种情况,因为第二种情况会给程序带来异常。接下来我就做动图分析了“对象消失”的情况


但是我是万万没想到呀,读者更关心的是“浮动垃圾”。有的读者就来问我,浮动垃圾是怎么产生的,你倒是给个图啊。


像我这样的又暖又有料的硬核原创作者,你说你要,那我肯定是要给你的。


下面就给你补上“浮动垃圾”的动图:


当并发标记完成后,对象图就变成了下面这个样子:


你看出来了吧。对象7,8,4,11,10都是浮动垃圾。因为他们被标记成了黑色,所以逃过了本次垃圾回收。


什么?你问我为什么黑色就不回收了?你个假粉丝,建议你先去读一读上周的文章。


G1垃圾回收时新对象怎么处理?


有的读者就提出了另外的很有探讨性的问题:


why哥你好,你《面试官:你说你熟悉jvm?那你讲一下并发的可达性分析》这篇文章主要解决了在并发标记阶段,GC线程和用户线程并发执行时,用户线程修改了对象引用关系,导致“对象消失”的问题。G1是采用原始快照加写前屏障的方式解决这个问题的。


但是我还有另外的一个问题:用户线程执行时不仅修改了对象引用关系,还新分配了新对象,我觉得这个情况是非常常见的,G1是如何找到并处理这些对象的呢?


换句话说,就是文章标题啦:G1收集器是怎么知道这些对象是什么时候应该进行垃圾标记的?


这是一个好问题,一看就是用心读了文章并带有自己的思考。很不错。


这位读者的问题属于第一个问题的连环炮,让我突然有了一种掉进了面试官布好的天罗地网里面的感觉。


面试官先故意漏出破绽,让你聊“对象消失”、“三色标记”、“增量更新”。然后等你得意洋洋的时候,突然抛出第二个问题:刚刚对象消失的问题回答的不错,那如果并发标记的时候用户线程分配了新对象,G1是怎么处理的呢?


说实话,我觉得只要你简历上没有写精通jvm,面试一般问到这种程度的我觉得是真的到了探讨的地步了。答的上来加分,答不上来也不扣分。


遥想2016年,我刚毕业,只身闯北京的时候,一连面试了9家公司,没有一家公司聊到 jvm (当然我当时面的是初级开发)。现在不一样了,不知道什么时候 jvm 从进阶面试题,变成了初级面试题。面试阶段如果没有问 jvm ,就感觉不是一次完整的面试。


我觉得就这几年面试题的变化,其实也就是反映了一个现象:想入行的人越来越多,导致入行的门槛越来越高。


不是jvm的地位变了,而是门槛越来越高了。


好了,瞎逼逼完了,接下来我们聊聊G1。


初识Garbage First(G1)


我不知道你是怎么知道G1的,但是我是从周志明大大的《深入理解Java虚拟机(第2版)》这本书里面第一次知道G1收集器的。


我记得当时读到G1的时候感觉这就是天书啊。


因为作者在介绍G1之前介绍了很多其他的收集器,我先给你看一下目录,带你回顾回顾:


可以看到,3.5.1节到3.5.6节介绍的收集器工作的时候, Java 堆的内存布局是按照新生代,老年代进行整体的区域划分的。


但是到了G1收集器, Java 堆的内存布局就有点"妖艳贱货"了。然后就有点越来越看不懂了,当时的场景就像下面这样:


它虽然还是保留的有新生代和老年代的概念,但是新生代和老年代之前再也不是区域上的隔离了。它将整个 Java 堆划分为多个大小相等的独立区域,叫做 Region 。而新生代和老年代就是由一个个 Region 动态组成的区域,它们可以是不连续的区间。


每一个 Region 都可以根据需要,扮演新生代的 Eden 空间,Survivor 空间,或者老年代空间。除此之外它还有一类特殊的区域叫做 Humongous,专门用来存储大对象。


上面说的是啥意思呢?其实用图片看起来就非常直观了:


比如对于 CMS,使用的堆内存结构如下:


可以看到上面的图片中不论是年轻代、老年代都是逻辑上连续的空间(但是不要求物理上的连续)。


而G1的堆内存被划分为多个大小相等的 Region ,但是 Region 的总个数在 2048 个左右,默认是 2048 。对于一个 Region 来说,是逻辑连续的一段空间,其大小的取值范围是 1MB 到 32MB 之间。


结构如下:


上面的E、S和没有写字母的蓝色方块(可以理解为old)没啥说的。


但是可以看到H是以往的垃圾收集器中没有的概念,它代表 Humongous,这表示这些 Region 存储的是巨型对象(humongous object,H-obj),当新建对象大小超过 Region 大小一半时,直接在新的一个或多个连续 Region 中分配,并标记为H。


说实话上面的这概念已经“烂大街”了,任何一篇写G1都会聊到,包括本文也是。


没办法啊,朋友们,这是引子,必须得先聊几句。就像斗地主,你第一手牌能直接出王炸吗?不能啊,你不得先来一个对三,循序渐进啊。


下面我送你一个小彩蛋吧。


注意到我上面说的几个数据了吗,2048个左右,1MB到32MB,这些数据是哪里来的呢,我说你就信了吗?


很多文章聊到G1的时候都只是说堆内存被划分为多个大小相等的 Region , Region 大小的取值范围为 1MB 到 32MB ,但是并没有提到 2048 这回事,我来给你寻根问祖一下:


我找到的第一个数据来源于上面的这篇论文,即文末的资料4:


The goal is to have around 2048 regions for the total heap.


这篇论文的作者是Monica Beckwith,你可以去搜一下,她(是的,我没打错,是个妹子)担任过Oracle G1 垃圾收集器性能团队 Leader,权威吧。


第二个数据来源当然是源码了,更权威吧:


http://hg.openjdk.java.net/jdk/jdk/file/fa2f93f99dbc/src/hotspot/share/gc/g1/heapRegionBounds.hpp


知道这个2048重要吗?我觉得不重要。


但是知道了就更牛逼呀!当妹子聊到2048的时候她只知道这是一个游戏,你要告诉她这个数字也是G1的Region的默认个数。


事了拂衣去,深藏功与名。

目录
相关文章
|
3月前
|
存储 监控 算法
美团面试:说说 G1垃圾回收 底层原理?说说你 JVM 调优的过程 ?
尼恩提示: G1垃圾回收 原理非常重要, 是面试的重点, 大家一定要好好掌握
美团面试:说说 G1垃圾回收 底层原理?说说你 JVM 调优的过程  ?
|
6月前
|
Java
Java面试题:什么是G1垃圾收集器,它如何改善性能?
Java面试题:什么是G1垃圾收集器,它如何改善性能?
66 0
Java 最常见的面试题:怎么判断对象是否可以被回收?
Java 最常见的面试题:怎么判断对象是否可以被回收?
|
存储 缓存 算法
13-大厂面试题:为什么要垃圾回收以及如何判断对象可以回收
接下来我们正式进入第二个系列,关于垃圾回收以及优化。
115 0
13-大厂面试题:为什么要垃圾回收以及如何判断对象可以回收
|
8月前
|
存储 算法 Java
[Java 源码] 秋招常被问到 GC 相关的几道面试题(集中在分配以及回收)
[Java 源码] 秋招常被问到 GC 相关的几道面试题(集中在分配以及回收)
|
8月前
|
监控 Java 程序员
GC(垃圾处理机制)面试加薪必备
GC(垃圾处理机制)面试加薪必备
66 0
|
存储 Java
【面试题精讲】JVM-方法区的回收
【面试题精讲】JVM-方法区的回收
|
算法 Java
【面试题精讲】为什么G1收集器不需要调优性能也很优秀
【面试题精讲】为什么G1收集器不需要调优性能也很优秀
|
算法 Java
第二季:1.JVM垃圾回收的时候如何确定垃圾?是否知道什么是GC Roots【Java面试题】
第二季:1.JVM垃圾回收的时候如何确定垃圾?是否知道什么是GC Roots【Java面试题】
109 0
|
存储 SQL 机器学习/深度学习
面试官:你这数据库表设计的,真垃圾。。。
面试官:你这数据库表设计的,真垃圾。。。