JVM垃圾收集-ZGC的染色指针

简介: 垃圾收集是回收以前分配的内存的机制, 以便将来的内存分配可以重用它。

前言:

🥂介绍染色指针之前,大家先回顾以下上一篇文章 《JVM垃圾收集-三色标记》,大部分追踪式垃圾收集器在并发标记阶段都采用了三色标记技术。但也有例外,比如:ZGC收集器有一个标志性的设计,就是采用了染色指针技术(Colored Pointer,其他类似的技术中可能将它称为Tag Pointer或者Version Pointer)。下面就来介绍一下染色指针。

应用场景

🌴🌴之前,如果我们要在对象上存储一些额外的、只供收集器或者虚拟机本身使用的数据,通常会在对象头中增加额外的存储字段,如对象的哈希码、分代年龄、锁记录等就是这样存储的。比如 64 位的 JVM,对象头的 Mark Word 中保存的信息如下图:

jm1.png

🎈这种记录方式在有对象访问的场景下是很自然流畅的,不会有什么额外负担。但如果有一些对象根本就不会去访问它,但又希望得知该对象的某些信息的场景呢?

我们就有这样的场景——追踪式收集算法的标记阶段就可能存在只跟指针打交道而不必涉及指针所引用的对象本身的场景。

🌰例如 对象标记的过程中需要给对象打上三色标记,这些标记本质上就只和对象的引用有关,而与对象本身无关——某个对象只有它的引用关系能决定它存活与否,对象上其他所有的属性都不能够影响它的存活判定结果。

👩HotSpot虚拟机的几种收集器有不同的标记实现方案:

  • 📍 把标记直接记录在对象头上(Serial收集器)
  • 📍 把标记记录在与对象相互独立的数据结构上(G1、Shenandoah使用了一种相当于堆内存的1/64大小的,称为BitMap的结构来记录标记信息)
  • 📍 ZGC的染色指针直接把标记信息记在引用对象的指针上(这个时候,与其说可达性分析是遍历对象图来标记对象,还不如说是遍历“引用图”来标记“引用”了。)


染色指针

染色指针是一种直接将少量额外的信息存储在指针上的技术。在 64 位 Linux 中,对象指针是 64 位,如下图:

jm2.png

👉🏻在这个 64 位的指针上,高 18 位都是 0,暂时不用来寻址。剩余的 46 位指针所能支持内存可以达到 64TB ,这可以满足多数大型服务器的需要了。不过 ZGC 并没有把 46 位都用来保存对象信息,而是用高 4 位保存了四个标志位,导致 ZGC 可以管理的最大内存不超过 4 TB 。

⭐⭐通过这四个标志位,JVM 可以从指针上直接看到对象的三色标记状态(Marked0、Marked1)、是否进入了重分配集(Remapped)、是否需要通过 finalize 方法来访问到(Finalizable)等信息。

无需进行对象访问就可以获得 GC 信息,这大大提高了 GC 效率。 🚀🚀🚀

🍺可以看到染色指针的优点已经很明显了。不过,要使用染色指针有一个必须解决的前置问题:Java虚拟机作为一个普普通通的进程,这样随意重新定义内存中某些指针的其中几位,操作系统是否支持?处理器是否支持?🤷‍

👩🏻‍程序代码最终都要转换为机器指令流交付给处理器去执行,处理器可不会管指令流中的指针哪部分存的是标志位,哪部分才是真正的寻址地址,只会把整个指针都视作一个内存地址来对待。

🎈在我们常用的x86-64平台上是不支持重新定义机器指令的,ZGC设计者们就采用了虚拟内存映射技术来解决这个问题。


虚拟内存映射

🍬在x86平台上,处理器会使用分页管理机制把线性地址空间物理地址空间分别划分为大小相同的块,这样的内存块被称为“页”(Page)。通过在线性虚拟空间的页与物理地址空间的页之间建立的映射表,分页管理机制会进行线性地址到物理地址空间的映射,完成线性地址到物理地址的转换。


✨简单的理解为:用 mmap 把不同的虚拟内存地址映射到同一个物理内存地址上。 如下图所示:

jm3.png

🍋ZGC 为了解决上面的寻址地址问题,使用了虚拟内存映射技术,把同一块儿物理内存映射为 Marked0、Marked1 和 Remapped 三个虚拟内存

🍹当应用程序创建对象时,会在堆上申请一个虚拟地址,这时 ZGC 会为这个对象在 Marked0、Marked1 和 Remapped 这三个视图空间分别申请一个虚拟地址,这三个虚拟地址映射到同一个物理地址。

🍦Marked0、Marked1 和 Remapped 这三个虚拟内存作为 ZGC 的三个视图空间,在同一个时间点内只能有一个有效。ZGC 就是通过这三个视图空间的切换,来完成并发的垃圾回收。

🙇好了关于染色指针的就介绍到这里,大家有什么疑问欢迎评论区讨论。

PS: 在 JDK 15 中 ,已经可以通过指令 –XX:+UseZGC 来启用采用染色指针技术的 ZGC收集器了。
🚀🚀🚀

目录
相关文章
|
3月前
|
存储 算法 Oracle
极致八股文之JVM垃圾回收器G1&ZGC详解
本文作者分享了一些垃圾回收器的执行过程,希望给大家参考。
|
1月前
|
存储 监控 算法
JVM调优深度剖析:内存模型、垃圾收集、工具与实战
【10月更文挑战第9天】在Java开发领域,Java虚拟机(JVM)的性能调优是构建高性能、高并发系统不可或缺的一部分。作为一名资深架构师,深入理解JVM的内存模型、垃圾收集机制、调优工具及其实现原理,对于提升系统的整体性能和稳定性至关重要。本文将深入探讨这些内容,并提供针对单机几十万并发系统的JVM调优策略和Java代码示例。
51 2
|
3月前
|
存储 算法 Java
JVM自动内存管理之垃圾收集算法
文章概述了JVM内存管理和垃圾收集的基本概念,提供一个关于JVM内存管理和垃圾收集的基础理解框架。
JVM自动内存管理之垃圾收集算法
|
3月前
|
存储 算法 Java
JVM组成结构详解:类加载、运行时数据区、执行引擎与垃圾收集器的协同工作
【8月更文挑战第25天】Java虚拟机(JVM)是Java平台的核心,它使Java程序能在任何支持JVM的平台上运行。JVM包含复杂的结构,如类加载子系统、运行时数据区、执行引擎、本地库接口和垃圾收集器。例如,当运行含有第三方库的程序时,类加载子系统会加载必要的.class文件;运行时数据区管理程序数据,如对象实例存储在堆中;执行引擎执行字节码;本地库接口允许Java调用本地应用程序;垃圾收集器则负责清理不再使用的对象,防止内存泄漏。这些组件协同工作,确保了Java程序的高效运行。
27 3
|
4月前
|
存储 算法 安全
(八)JVM成神路之GC分区篇:G1、ZGC、ShenandoahGC高性能收集器深入剖析
在《GC分代篇》中,我们曾对JVM中的分代GC收集器进行了全面阐述,而在本章中重点则是对JDK后续新版本中研发推出的高性能收集器进行深入剖析。
162 12
|
3月前
|
C# UED 开发者
WPF打印功能实现秘籍:从页面到纸张,带你玩转WPF打印技术大揭秘!
【8月更文挑战第31天】在WPF应用开发中,打印功能至关重要,不仅能提升用户体验,还增强了应用的实用性。本文介绍WPF打印的基础概念与实现方法,涵盖页面元素打印、打印机设置及打印预览。通过具体案例,展示了如何利用`PrintDialog`和`PrintDocument`控件添加打印支持,并使用`PrinterSettings`类进行配置,最后通过`PrintPreviewWindow`实现打印预览功能。
321 0
|
3月前
|
C# UED 开发者
WPF动画大揭秘:掌握动画技巧,让你的界面动起来,告别枯燥与乏味!
【8月更文挑战第31天】在WPF应用开发中,动画能显著提升用户体验,使其更加生动有趣。本文将介绍WPF动画的基础知识和实现方法,包括平移、缩放、旋转等常见类型,并通过示例代码展示如何使用`DoubleAnimation`创建平移动画。此外,还将介绍动画触发器的使用,帮助开发者更好地控制动画效果,提升应用的吸引力。
179 0
|
3月前
|
算法 Java 程序员
【JVM的秘密花园】揭秘垃圾收集器的神秘面纱!
【8月更文挑战第25天】在Java虚拟机(JVM)中,垃圾收集(GC)自动管理内存,回收未使用的对象以避免内存泄漏和性能下降。本文深入介绍了JVM中的GC算法,包括串行、并行、CMS及G1等类型及其工作原理。选择合适的GC策略至关重要:小型应用适合串行收集器;大型应用或多核CPU环境推荐并行收集器或CMS;需减少停顿时间时,CMS是好选择;G1适用于大堆且对停顿时间敏感的应用。理解这些能帮助开发者优化程序性能和稳定性。
37 0
|
3月前
|
算法 Java
JVM自动内存管理之垃圾收集器
这篇文章是关于Java虚拟机(JVM)自动内存管理中的垃圾收集器的详细介绍。
|
4月前
|
监控 算法 Java
深入理解Java虚拟机:垃圾收集机制的演变与最佳实践
【7月更文挑战第14天】本文将带领读者穿梭于JVM的心脏——垃圾收集器,探索其设计哲学、实现原理和性能调优。我们将从早期简单的收集算法出发,逐步深入到现代高效的垃圾收集策略,并分享一些实用的调优技巧,帮助开发者在编写和维护Java应用时做出明智的决策。
50 3