美团面试官问我: ZGC 的 Z 是什么意思(中)

简介: 美团面试官问我: ZGC 的 Z 是什么意思(中)

Using colored pointers


染色指针其实就是从 64 位的指针中,拿几位来标识对象此时的情况,分别表示 Marked0、Marked1、Remapped、Finalizable。


image.png

0-41 这 42 位就是正常的地址,所以说 ZGC 最大支持 4TB (理论上可以16TB)的内存,因为就 42 位用来表示地址。

也因此 ZGC 不支持 32 位指针,也不支持指针压缩。

然后用 42-45 位来作为标志位,其实不管这个标志位是啥指向的都是同一个对象。

这是通过多重映射来做的,很简单就是多个虚拟地址指向同一个物理地址,不过对象地址是 0001.... 还是0010....还是0100..... 对应的都是同一个物理地址即可。

具体这几个标记位怎么用的,待下文回收流程分析再解释。

不过这里先提个问题,为什么就支持 4TB,不是还有很多位没用吗

首先 X86_64 的地址总线只有 48 条 ,所以最多其实只能用 48 位,指令集是 64 位没错,但是硬件层面就支持 48 位。

因为基本上没有多少系统支持这么大的内存,那支持 64 位就没必要了,所以就支持到 48 位。

那现在对象地址就用了 42 位,染色指针用了 4 位,不是还有 2 位可以用吗?

是的,理论上可以支持 16 TB,不过暂时认为 4TB 够了,所以暂做保留,仅此而已没啥特别的含义。


Using load barriers


在 CMS 和 G1 中都用到了写屏障,而 ZGC 用到了读屏障。

写屏障是在对象引用赋值时候的 AOP,而读屏障是在读取引用时的 AOP。

比如 Object a = obj.foo;,这个过程就会触发读屏障。

也正是用了读屏障,ZGC 可以并发转移对象,而 G1 用的是写屏障,所以转移对象时候只能 STW。

简单的说就是 GC 线程转移对象之后,应用线程读取对象时,可以利用读屏障通过指针上的标志来判断对象是否被转移。

如果是的话修正对象的引用,按照上面的例子,不仅 a 能得到最新的引用地址,obj.foo 也会被更新,这样下次访问的时候一切都是正常的,就没有消耗了。

下图展示了读屏障的效果,其实就是转移的时候找地方记一下即 forwardingTable,然后读的时候触发引用的修正。


image.png

这种也称之为“自愈”,不仅赋值的引用时最新的,自身引用也修正了。

染色指针和读屏障是 ZGC 能实现并发转移的关键所在


ZGC 回收流程解析


ZGC 的步骤大致可分为三大阶段分别是标记、转移、重定位。

  • 标记:从根开始标记所有存活对象
  • 转移:选择部分活跃对象转移到新的内存空间上
  • 重定位:因为对象地址变了,所以之前指向老对象的指针都要换到新对象地址上。

并且这三个阶段都是并发的。

这是意识上的阶段,具体的实现上重定位其实是糅合在标记阶段的

在标记的时候如果发现引用的还是老的地址则会修正成新的地址,然后再进行标记。

简单的说就是从第一个 GC 开始经历了标记,然后转移了对象,这个时候不会重定位,只会记录对象都转移到哪里了。

在第二个 GC 开始标记的时候发现这个对象是被转移了,然后发现引用还是老的,则进行重定位,即修改成新的引用。

所以说重定位是糅合在下一步的标记阶段中。

image.png


我再简单说一下十个步骤。

不过步骤里有些不影响整体回收流程的,我就不多加分析了。

这篇文章的目的不是深入 ZGC 实现的细节,而是了解 ZGC 大致的突出点和简单流程即可

因此想知道细节的自行查阅,或者可以看看我文末推荐的书籍。


初始标记


这个阶段其实大家应该很熟悉,CMS、G1 都有这个阶段,这个阶段是 STW 的,仅标记根直接可达的对象,压到标记栈中

当然还有其他动作,比如重置 TLAB、判断是否要清除软引用等等,不做具体分析。


并发标记


就是根据初始标记的对象开始并发遍历对象图,还会统计每个 region 的存活对象的数量。

这个并发标记其实有个细节,标记栈其实只有一个,但是并发标记的线程有多个。

为了减少之间的竞争每个线程其实会分到不同的标记带来执行。

你就理解为标记栈被分割为好几块,每个线程负责其中的一块进行遍历标记对象,就和1.7 Hashmap 的segment 一样。

那肯定有的线程标记的快,有的标记的慢,那么先空闲下来的线程会去窃取别人的任务来执行,从而实现负载均衡。

看到这有没有想到啥?没错就是 ForkJoinPool 的工作窃取机制!


再标记阶段


这一阶段是 STW 的,因为并发阶段应用线程还是在运行的,所以会修改对象的引用导致漏标的情况。

因此需要个再标记阶段来标记漏标的那些对象。

如果这个阶段执行的时间过长,就会再次进入到并发标记阶段,因为 ZGC 的目标就是低延迟,所以一有高延迟的苗头就得扼制。

这个阶段还会做非强根并行标记,非强根指的是:系统字典、JVMTI、JFR、字符串表。

有些非强根可以并发,有些不行,具体不做分析。


非强引用并发标记和引用并发处理


就是上一步非强根的遍历,然后引用就软引用、弱引用、虚引用的一些处理。

这个阶段是并发的。


重置转移集


还记得标记时候的重定位么?在写读屏障时候提到的 forwardingTable 就是个映射集,你可以理解为 key 就是对象转移前的地址,value 是对象转移后的地址。

不过这个映射集在标记阶段已经用了,也就是说标记的时候已经重定位完了,所以现在没用了。

但新一轮的垃圾回收需要还是要用到这个映射集的。

因此在这个阶段对那些转移分区的地址映射集做一个复位的操作。


回收无效分区


回收那些物理内存已经被释放的无效的虚拟内存页面。

就是在内存紧张的时候会释放物理内存,如果同时释放虚拟空间的话也不能释放分区,因为分区需要在新一轮标记完成之后才能释放

所以就会有无效的虚拟内存页面存在,在这个阶段回收。


选择待回收的分区


这和 G1 一样,因为会有很多可以回收的分区,会筛选垃圾较多的分区,来作为这次回收的分区集合。


初始化待转移集合的转移表


这一步就是初始化待回收的分区的 forwardingTable。



相关文章
|
1月前
|
存储 安全 Java
每日大厂面试题大汇总 —— 今日的是“美团-后端开发-一面”
文章汇总了美团后端开发一面的面试题目,内容涉及哈希表、HashMap、二叉树遍历、数据库索引、死锁、事务隔离级别、Java对象相等性、多态、线程池拒绝策略、CAS、设计模式、Spring事务传播机制及RPC序列化工具等。
47 0
|
22天前
|
SQL 缓存 关系型数据库
美团面试:Mysql 有几级缓存? 每一级缓存,具体是什么?
在40岁老架构师尼恩的读者交流群中,近期有小伙伴因未能系统梳理MySQL缓存机制而在美团面试中失利。为此,尼恩对MySQL的缓存机制进行了系统化梳理,包括一级缓存(InnoDB缓存)和二级缓存(查询缓存)。同时,他还将这些知识点整理进《尼恩Java面试宝典PDF》V175版本,帮助大家提升技术水平,顺利通过面试。更多技术资料请关注公号【技术自由圈】。
美团面试:Mysql 有几级缓存? 每一级缓存,具体是什么?
|
1月前
|
算法 Java 数据库
美团面试:百亿级分片,如何设计基因算法?
40岁老架构师尼恩分享分库分表的基因算法设计,涵盖分片键选择、水平拆分策略及基因法优化查询效率等内容,助力面试者应对大厂技术面试,提高架构设计能力。
美团面试:百亿级分片,如何设计基因算法?
|
1月前
|
存储 监控 算法
美团面试:说说 G1垃圾回收 底层原理?说说你 JVM 调优的过程 ?
尼恩提示: G1垃圾回收 原理非常重要, 是面试的重点, 大家一定要好好掌握
美团面试:说说 G1垃圾回收 底层原理?说说你 JVM 调优的过程  ?
|
1月前
|
SQL 存储 关系型数据库
美团面试:binlog、redo log、undo log的底层原理是什么?它们分别实现ACID的哪个特性?
老架构师尼恩在其读者交流群中分享了关于 MySQL 中 redo log、undo log 和 binlog 的面试题及其答案。这些问题涵盖了事务的 ACID 特性、日志的一致性问题、SQL 语句的执行流程等。尼恩详细解释了这些日志的作用、所在架构层级、日志形式、缓存机制以及写文件方式等内容。他还提供了多个面试题的详细解答,帮助读者系统化地掌握这些知识点,提升面试表现。此外,尼恩还推荐了《尼恩Java面试宝典PDF》和其他技术圣经系列PDF,帮助读者进一步巩固知识,实现“offer自由”。
美团面试:binlog、redo log、undo log的底层原理是什么?它们分别实现ACID的哪个特性?
|
24天前
|
SQL 关系型数据库 MySQL
美团面试:Mysql如何选择最优 执行计划,为什么?
在40岁老架构师尼恩的读者交流群中,近期有小伙伴面试美团时遇到了关于MySQL执行计划的面试题:“MySQL如何选择最优执行计划,为什么?”由于缺乏系统化的准备,小伙伴未能给出满意的答案,面试失败。为此,尼恩为大家系统化地梳理了MySQL执行计划的相关知识,帮助大家提升技术水平,展示“技术肌肉”,让面试官“爱到不能自已”。相关内容已收录进《尼恩Java面试宝典PDF》V175版本,供大家参考学习。
|
1月前
|
算法 Java 数据库
美团面试:百亿级分片,如何设计基因算法?
40岁老架构师尼恩在读者群中分享了关于分库分表的基因算法设计,旨在帮助大家应对一线互联网企业的面试题。文章详细介绍了分库分表的背景、分片键的设计目标和建议,以及基因法的具体应用和优缺点。通过系统化的梳理,帮助读者提升架构、设计和开发水平,顺利通过面试。
美团面试:百亿级分片,如何设计基因算法?
|
1月前
|
消息中间件 存储 缓存
美团面试: Kafka为啥能实现 10Wtps 到100Wtps ?kafka 如何实现零复制 Zero-copy?
40岁老架构师尼恩分享了Kafka如何实现高性能的秘诀,包括零拷贝技术和顺序写。Kafka采用mmap和sendfile两种零拷贝技术,前者用于读写索引文件,后者用于向消费者发送消息,减少数据在用户空间和内核空间间的拷贝次数,提高数据传输效率。此外,Kafka通过顺序写日志文件,避免了磁盘寻道和旋转延迟,进一步提升了写入性能。尼恩还提供了系列技术文章和PDF资料,帮助读者深入理解这些技术,提升面试竞争力。
美团面试: Kafka为啥能实现 10Wtps 到100Wtps ?kafka 如何实现零复制 Zero-copy?
|
1月前
|
NoSQL Java API
美团面试:Redis锁如何续期?Redis锁超时,任务没完怎么办?
在40岁老架构师尼恩的读者交流群中,近期有小伙伴在面试一线互联网企业时遇到了关于Redis分布式锁过期及自动续期的问题。尼恩对此进行了系统化的梳理,介绍了两种核心解决方案:一是通过增加版本号实现乐观锁,二是利用watch dog自动续期机制。后者通过后台线程定期检查锁的状态并在必要时延长锁的过期时间,确保锁不会因超时而意外释放。尼恩还分享了详细的代码实现和原理分析,帮助读者深入理解并掌握这些技术点,以便在面试中自信应对相关问题。更多技术细节和面试准备资料可在尼恩的技术文章和《尼恩Java面试宝典》中获取。
美团面试:Redis锁如何续期?Redis锁超时,任务没完怎么办?
|
1月前
|
SQL 关系型数据库 MySQL
美团面试:mysql 索引失效?怎么解决? (重点知识,建议收藏,读10遍+)
本文详细解析了MySQL索引失效的多种场景及解决方法,包括破坏最左匹配原则、索引覆盖原则、前缀匹配原则、`ORDER BY`排序不当、`OR`关键字使用不当、索引列上有计算或函数、使用`NOT IN`和`NOT EXISTS`不当、列的比对等。通过实例演示和`EXPLAIN`命令分析,帮助读者深入理解索引失效的原因,并提供相应的优化建议。文章还推荐了《尼恩Java面试宝典》等资源,助力面试者提升技术水平,顺利通过面试。
下一篇
无影云桌面