Shenandoah收集器和ZGC收集器

2023-10-27 19:59
文章标签 收集器 zgc shenandoah

本文主要是介绍Shenandoah收集器和ZGC收集器,希望对大家解决编程问题提供一定的参考价值,需要的开发者们随着小编来一起学习吧!

Shenandoah收集器

与G1相比它的特点如下:

  • 支持并发的整理算法
  • 不会有专门的新生代Region或者老年代Region的存在,没有实现分代,并不是说分代对Shenandoah没有价值,这更多是出于性价比的权衡,基于工作量上的考虑而将其放到优先级较低的位置上。
  • 在G1中耗费大量内存和计算资源去维护的记忆集,改用名为“连接矩阵”。(连接矩阵可以简单理解为一张二维表格,如果Region N有
    对象指向Region M,就在表格的N行M列中打上一个标记)。
  • 用到了读屏障,读屏障是为了防止内存中对象移动时候,用户线程可能通过引用读到的是正在移动的内存块,会读到错误的数据。此时有两种方法:1.整理内存时候直接SWT,暂停用户线程。2.利用读屏障,记录每次读取到的值。在对象移动的时候,用户线程就直接读屏障中每次记录的值,而用去读取引用指向的那块可能正在移动的内存。

工作流程如下:

  • 初始标记
  • 并发标记
  • 最终标记
  • 并发清理:这个阶段用于清理那些整个区域内连一个存活对象都没有找到
    的Region(这类Region被称为Immediate Garbage Region)。
  • 并发回收
  • 初始引用更新
  • 并发引用更新
  • 最终引用更新
  • 并发清理

并发回收阶段是Shenandoah与之前HotSpot中其他收集器的核心差异。在这个阶段,Shenandoah要把回收集里面的存活对象先复制一份到其他未被使用的Region之中。复制对象这件事情如果将用户线程冻结起来再做那是相当简单的,但如果两者必须要同时并发进行的话,就变得复杂起来了。其困难点是在移动对象的同时,用户线程仍然可能不停对被移动的对象进行读写访问,移动对象是一次性的行为,但移动之后整个内存中所有指向该对象的引用都还是旧对象的地址,这是很难一瞬间全部改变过来的。

Shenandoah收集器使用转发指针来实现并发回收。在此之前,要做类似的并发操作,通常是在被移动对象原有的内存上设置保护陷阱(MemoryProtection Trap),一旦用户程序访问到归属于旧对象的内存空就会产生自陷中段,进入预设好的异常处理器中,再由其中的代码逻辑把访问转发到复制后的新对象上。虽然确实能够实现对象移动与用户线程并发,但是如果没有操作系统层面的直接支持,这种方案将导致用户态频繁切换到核心态,代价是非常大的,不能频繁使用。
转发指针:在原有对象布局结构的最前面统一增加一个新的引用字段,在正常不处于并发移动的情况下,该引用指向对象自己
如图所示:
在这里插入图片描述
转发指针加入后带来的收益自然是当对象拥有了一份新的副本时,只需要修
改一处指针的值,即旧对象上转发指针的引用位置,使其指向新对象,便可将所有对该对象的访问转发到新的副本上。这样只要旧对象的内存仍然存在,未被清理掉,虚拟机内存中所有通过旧引用地址访问的代码便仍然可用,都会被自动转发到新对象上继续工作,如图所示:
在这里插入图片描述
需要注意,Brooks形式的转发指针在设计上决定了它是必然会出现多线程竞争问题的,如果收集器线程与用户线程发生的只是并发读取,那无论读到旧对象还是新对象上的字段,返回的结果都应该是一样的,这个场景还可以有一些“偷懒”的处理余地;但如果发生的是并发写入,就一定必须保证写操作只能发生在新复制的对象上,而不是写入旧对象的内存中。读者不妨设想以下三件事情并发进行时的场景:

  1. 收集器线程复制了新的对象副本;
  2. 用户线程更新对象的某个字段;
  3. 收集器线程更新转发指针的引用值为新副本地址。

如果不做任何保护措施,让事件2在事件1、事件3之间发生的话,将导致的结果就是用户线程对对象的变更发生在旧对象上,所以这里必须针对转发指针的访问操作采取同步措施,让收集器线程或者用户线程对转发指针的访问只有其中之一能够成功,另外一个必须等待,避免两者交替进行。

ZGC收集器

特点:

  • 不设分代
  • 使用了读屏障、染色指针和内存多重映射等技术来实现可并发的标记-整理算法。

染色指针是一种直接将少量额外的信息存储在指针上的技术。(虚拟内存映射为基础实现)

  • 染色指针可以使得一旦某个Region的存活对象被移走之后,这个Region立即就能够被释放和重用掉,而不必等待整个堆中所有指向该Region的引用都被修正后才能清理。
  • 染色指针可以大幅减少在垃圾收集过程中内存屏障的使用数量。
  • ·染色指针可以作为一种可扩展的存储结构用来记录更多与对象标记、重定位过程相关的数据,以便日后进一步提高性能。

工作流程:

  • 初始标记
  • 并发标记
  • 最终标记
  • 并发预备重分配
  • 并发重分配
  • 并发重映射

ZGC的标记是在指针上而不是在对象上进行的,标记阶段会更新染色指针中的Marked 0、Marked 1标志位。

重分配是ZGC执行过程中的核心阶段,这个过程要把重分配集中的存活对象复制到新的Region上,并为重分配集中的每个Region维护一个转发表(ForwardTable),记录从旧对象到新对象的转向关系。得益于染色指针的支持,ZGC收集器能仅从引用上就明确得知一个对象是否处于重分配集之中,如果用户线程此时并发访问了位于重分配集中的对象,这次访问将会被预置的内存屏障所截获,然后立即根据Region上的转发表记录将访问转发到新复制的对象上,并同时修正更新该引用的值,使其直接指向新对象,ZGC将这种行为称为指针的“自愈”(SelfHealing)能力。这样做的好处是只有第一次访问旧对象会陷入转发,也就是只慢一次,对比Shenandoah的Brooks转发指针,那是每次对象访问都必须付出的固定开销,简单地说就是每次都慢,因此ZGC对用户程序的运行时负载要比Shenandoah来得更低一些。还有另外一个直接的好处是由于染色指针的存在,一旦重分配集中某个Region的存活对象都复制完毕后,这个Region就可以立即释放用于新对象的分配(但是转发表还得留着不能释放掉),哪怕堆中还有很多指向这个对象的未更新指针也没有关系,这些旧指针一旦被使用,它们都是可以自愈的。

这篇关于Shenandoah收集器和ZGC收集器的文章就介绍到这儿,希望我们推荐的文章对编程师们有所帮助!



http://www.chinasem.cn/article/288039

相关文章

【编程底层思考】垃圾收集机制,GC算法,垃圾收集器类型概述

Java的垃圾收集(Garbage Collection,GC)机制是Java语言的一大特色,它负责自动管理内存的回收,释放不再使用的对象所占用的内存。以下是对Java垃圾收集机制的详细介绍: 一、垃圾收集机制概述: 对象存活判断:垃圾收集器定期检查堆内存中的对象,判断哪些对象是“垃圾”,即不再被任何引用链直接或间接引用的对象。内存回收:将判断为垃圾的对象占用的内存进行回收,以便重新使用。

HotSpot虚拟机的经典垃圾收集器

读《深入理解Java虚拟机》第三版笔记。 关系 Serial、ParNew、Parallel Scavenge、Parallel Old、Serial Old(MSC)、Concurrent Mark Sweep (CMS)、Garbage First(G1)收集器。 如图: 1、Serial 和 Serial Old 收集器 2、ParNew 收集器 3、Parallel Sc

Spark学习之路 (十四)SparkCore的调优之资源调优JVM的GC垃圾收集器

《2021年最新版大数据面试题全面开启更新》 欢迎关注github《大数据成神之路》 目录 一、概述 二、垃圾收集器(garbage collector (GC)) 是什么? 三、为什么需要GC? 四、为什么需要多种GC? 五、对象存活的判断 六、垃圾回收算法 6.1 标记 -清除算法 6.2 复制算法 6.3 标记-整理算法 6.4 分代收集算法 七、垃圾收集器 7.1 Serial收集器

JVM性能调优之5种垃圾收集器

JDK垃圾收集器 一、Serial GC垃圾收集器Serial GC的工作原理Serial GC的特点Serial GC的配置参数Serial GC的适用场景Serial GC的优缺点优点:缺点: Serial GC的总结 二、Parallel GC垃圾收集器Parallel GC的工作原理Parallel GC的特点Parallel GC的配置参数Parallel GC的适用场景Paral

Java虚拟机(JVM)中各种垃圾收集器的优缺点总结

下面是一个详细的表格,总结了Java虚拟机(JVM)中各种垃圾收集器的优缺点,并包括了它们的诞生时间: 垃圾收集器诞生时间优点缺点Serial GCJDK 1.2- 简单易实现- 适用于单处理器系统或小型应用- 低内存占用- 停顿时间长- 不适用于多核处理器或需要低延迟的应用Parallel GCJDK 1.4- 提高吞吐量- 适用于多处理器系统- 减少停顿时间- 在多线程环境下仍可能导致较长的

深入理解 JVM垃圾收集算法和垃圾收集器(一篇就够)

一、概述 在Java中内存是由JVM虚拟机自动管理的,JVM在内存中划出一片区域,作为满足程序内存分配请求的空间。内存的创建仍然是由程序猿来显示指定的,但是对象的释放却对程序猿是透明的。就是解放了程序猿手动回收内存的工作,交给垃圾回收器来自动回收。 在JVM虚拟机中,释放哪些不再被使用的对象所占空间的过程称为垃圾收集(Garbage Collection,GC)。负责垃圾收集的程序模块被称为垃

垃圾收集器知识点总结-MaxTenuringThreshold

MaxTenuringThreshold该参数用于控制对象经过GC多少次仍然存活后晋升到老年代的最大阈值,参数最大可配置为15,即对象最多经过15次GC后仍然存活就会晋升到老年代 记住!是最大!也就是说实际上不一定会经过15次才能晋升!这个值的JVM内部会进行动态计算然后动态改变的。 最近在线上有个应用GC非常频繁,MaxTenuringThreshold参数配置的是15,而以前对这个参数的理

垃圾收集器知识点总结-CMS

使用回收算法:标记清除 适用区域:老年代 回收过程: 1.初始化标记: 标记Root可达的对象。对于是否把年轻带作为root的这个问题,有不同答案,但是看到了代码里初始化标记的时候做了如下操作 初始化标记会执行到上述代码,然后第二个变量是true(可能对代码的理解有偏差) 2.并发标记: 标记新生代活的对象为Root;沿着Root标记存活的对象;在与程序运行期间,对象引用关系会变化,

深入理解JVM之垃圾收集器与内存分配策略

读完JVM的第三章最大的收获是知道了垃圾收集的算法,了解了JDK1.7中提供的垃圾收集器的特点以及运作原理,通过代码实例验证了Java虚拟机中自动分配内存及回收的主要规则。了解了内存回收与垃圾收集器在很多时候都是影响系统性能、并发能力的主要因素之一,虚拟机之所以提供多种不同的收集器以及提供大量的调节参数,是因为只有根据实际应用需求,实现方式选择最优的收集方式才能获取最高的性能。没有固定

jvm的垃圾收集器整理

首先我们先根据下面这个图来具体说下每个收集器的特点: serial收集器: Serial(串行)收集器收集器是最基本、历史最悠久的垃圾收集器了。大家看名字就知道这个收集器是一个单线程收集器了。它的 “单线程” 的意义不仅仅意味着它只会使用一条垃圾收集线程去完成垃圾收集工作,更重要的是它在进行垃圾收集工作的时候必须暂停其他所有的工作线程( “Stop The World” ),直到它收集结束