JVM垃圾回收-三色标记

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

🍋 这次给大家介绍一下JVM垃圾回收可达性分析算法的实现原理。

🎈🎈🎈上篇文章《JVM垃圾回收-记忆集和卡表》 已经和大家介绍了JVM是如何快速的扫描和标记GC Roots的。标记 完GC Roots之后,JVM就需要从GC Roots开始遍历整个对象图了(即并发标记的过程)。

那么JVM又是如何遍历对象图的呢?

☕现代大多数跟踪垃圾收集器(如CMS、G1、Shenandoah)都实现[三色标记]{.blue}抽象的一些变体来对“垃圾”进行标记的。之所以都选择三色标记是因为它能够解决或者降低用户线程的停顿时间。 🚀🚀🚀

下面就进入本文正题:

三色标记

☘三色标记算法把遍历对象图过程中遇到的对象,按照“是否被访问过”分为以下三种颜色:

  • 白色✨: 表示对象尚未被垃圾收集器访问过。 [(显然在可达性分析刚刚开始的阶段,所有的对象都是白色的,若在分析结束的阶段,仍然是白色的对象,即代表不可达)]{.grey}
  • 灰色✨: 表示对象已经被垃圾收集器访问过,但这个对象上至少存在一个引用还没有被扫描过。
  • 黑色✨: 表示对象已经被垃圾收集器访问过,且这个对象的所有引用都已经扫描过。 [(黑色的对象代表已经扫描过,它是安全存活的,如果有其他对象引用指向了黑色对象,无须重新扫描一遍。黑色对象不可能直接(不经过灰色对象)指向某个白色对象)]{.grey}

🌴🌴下面来看一下三色标记遍历对象图的大致过程:
jjm.gif

⭐初始状态只有GC Roots是黑色的。被GC Roots直接引用的对象会变成灰色

⭐扫描过程中,按照以下两点扫描整个引用链

  • 当前灰色节点没有子节点的话,将当前节点变为黑色。
  • 当前灰色节点有子节点的话,当前节点变为黑色,且子节点变为灰色。

⭐扫描完成时,黑色对象就是存活的对象,白色对象就是已消亡可回收的对象

扫描完成之后,垃圾收集器只需要回收仍然是白色的对象所占用的内存即可。乍一看上面的过程好像没有什么问题,但是不要忘了我们的[收集线程是和用户线程并发执行的]{.green}。🚀🚀🚀

🌻🌻那么就会遇到一些问题了,我们的收集器在对象图上标记颜色的同时,用户线程在修改引用关系——即修改对象图的结构,这样可能会出现下面两种后果:

📍一种是把原本消亡的对象错误标记为存活,这不是好事,但其实是可以容忍的,只不过产生了一点逃过本次收集的浮动垃圾而已,下次收集清理掉就好。

📍另一种是把原本存活的对象错误标记为已消亡,这就是非常致命的后果了,程序肯定会因此发生错误。

下面来演示一下上面的错误具体是如何产生的。

第一种:浮动垃圾

🍺假设 GC 线程已经遍历到 E(变为灰色了),此时D > E 的引用断开:

jjm1.png

D > E 的引用断开之后,E、H、G 三个对象不可达,应该要被回收的。然而因为 E 已经变为灰色了,其仍会被当作存活对象继续遍历下去。最终的结果是:这部分对象仍会被标记为存活,即本轮 GC 不会回收这部分内存。

👩这部分本应该回收但是没有回收到的内存,被称之为浮动垃圾。浮动垃圾并不会影响应用程序的正确性,下次收集时清理掉就好。


第二种:“对象消失”

🍬假设 GC 线程已经遍历到 E(变为灰色了),此时E > G 的引用断开,新增D > G 的引用:

jjm2.png

👀此时因为 E 已经没有对 G 的引用了,所以不会将 G 置为灰色;尽管因为 D 重新引用了 G,但因为 D 已经是黑色了,不会再重新做遍历处理。

🍑最终导致的结果是:G 会一直是白色,最后被当作垃圾进行清除。这就是非常致命的后果了,程序肯定会因此发生错误,是不可以接受的。


🥇我们很容易看到发生这种错误是需要同时满足以下两个条件才可以成立的:

第一个条件: 赋值器插入了一条或多条从黑色对象到白色对象的新引用。(即新增D > G 的引用)

第二个条件: 赋值器删除了全部从灰色对象到该白色对象的直接或间接引用。(即断开E > G 的引用)

🍹我们要解决这个问题,只需破坏这两个条件中的任意一个条件 即可避免发生并发扫描时的对象消失问题。


🍍🍍先来破坏第一个条件,当黑色对象插入新的指向白色对象的引用关系时,我们就可以将这个新插入的引用记录下来,等并发扫描结束之后,再将这些记录过的引用关系中的黑色对象为根,重新扫描一次。这可以简化理解为,黑色对象一旦新插入了指向白色对象的引用之后,它就变回灰色对象了。 这种解决方案称为增量更新

🍉🍉也可以破坏第二个条件,当灰色对象要删除指向白色对象的引用关系时,我们就将这个要删除的引用记录下来,在并发扫描结束之后,再将这些记录过的引用关系中的灰色对象为根,重新扫描一次。这也可以简化理解为,无论引用关系删除与否,都会按照刚刚开始扫描那一刻的对象图快照来进行搜索。 这种解决方案称为原始快照


😎无论采用哪一种方案,都可以解决上面的问题。在HotSpot虚拟机中,增量更新和原始快照这两种解决方案都有实际应用,譬如,CMS就是基于增量更新来做并发标记的,G1、Shenandoah则是用原始快照方式来实现。

🙇读完上面的内容,相信大家已经对JVM并发标记的过程有了一定的了解。JVM虚拟机标记完不可达对象之后还需要对这些对象所占用的内存进行回收,具体的回收动作是由虚拟机采用哪款垃圾回收器所决定的。

🚀🚀🚀

目录
相关文章
|
2天前
|
监控 算法 Java
Java虚拟机(JVM)的垃圾回收机制深度解析####
本文深入探讨了Java虚拟机(JVM)的垃圾回收机制,旨在揭示其背后的工作原理与优化策略。我们将从垃圾回收的基本概念入手,逐步剖析标记-清除、复制算法、标记-整理等主流垃圾回收算法的原理与实现细节。通过对比不同算法的优缺点及适用场景,为开发者提供优化Java应用性能与内存管理的实践指南。 ####
|
1月前
|
缓存 算法 Java
JVM知识体系学习六:JVM垃圾是什么、GC常用垃圾清除算法、堆内存逻辑分区、栈上分配、对象何时进入老年代、有关老年代新生代的两个问题、常见的垃圾回收器、CMS
这篇文章详细介绍了Java虚拟机(JVM)中的垃圾回收机制,包括垃圾的定义、垃圾回收算法、堆内存的逻辑分区、对象的内存分配和回收过程,以及不同垃圾回收器的工作原理和参数设置。
65 4
JVM知识体系学习六:JVM垃圾是什么、GC常用垃圾清除算法、堆内存逻辑分区、栈上分配、对象何时进入老年代、有关老年代新生代的两个问题、常见的垃圾回收器、CMS
|
1月前
|
存储 监控 算法
美团面试:说说 G1垃圾回收 底层原理?说说你 JVM 调优的过程 ?
尼恩提示: G1垃圾回收 原理非常重要, 是面试的重点, 大家一定要好好掌握
美团面试:说说 G1垃圾回收 底层原理?说说你 JVM 调优的过程  ?
|
1月前
|
算法 Java
谈谈HotSpot JVM 中的不同垃圾回收器
【10月更文挑战第5天】理解 HotSpot JVM 中的不同垃圾回收器(如 CMS、G1 和 ZGC)的区别,需要深入了解它们的设计原理、工作方式和应用场景。以下是对这三个垃圾回收器的简要概述以及一个示例 Java 程序,虽然示例程序本身不能直接展示垃圾回收器的内部机制,但可以帮助观察不同垃圾回收器的行为。
25 1
|
1月前
|
存储 算法 Java
【JVM】垃圾释放方式:标记-清除、复制算法、标记-整理、分代回收
【JVM】垃圾释放方式:标记-清除、复制算法、标记-整理、分代回收
50 2
|
2月前
|
存储 算法 Java
深入解析 Java 虚拟机:内存区域、类加载与垃圾回收机制
本文介绍了 JVM 的内存区域划分、类加载过程及垃圾回收机制。内存区域包括程序计数器、堆、栈和元数据区,每个区域存储不同类型的数据。类加载过程涉及加载、验证、准备、解析和初始化五个步骤。垃圾回收机制主要在堆内存进行,通过可达性分析识别垃圾对象,并采用标记-清除、复制和标记-整理等算法进行回收。此外,还介绍了 CMS 和 G1 等垃圾回收器的特点。
112 0
深入解析 Java 虚拟机:内存区域、类加载与垃圾回收机制
|
1月前
|
存储 Java PHP
【JVM】垃圾回收机制(GC)之引用计数和可达性分析
【JVM】垃圾回收机制(GC)之引用计数和可达性分析
60 0
|
1月前
|
存储 安全 Java
jvm 锁的 膨胀过程?锁内存怎么变化的
【10月更文挑战第3天】在Java虚拟机(JVM)中,`synchronized`关键字用于实现同步,确保多个线程在访问共享资源时的一致性和线程安全。JVM对`synchronized`进行了优化,以适应不同的竞争场景,这种优化主要体现在锁的膨胀过程,即从偏向锁到轻量级锁,再到重量级锁的转变。下面我们将详细介绍这一过程以及锁在内存中的变化。
37 4
|
11天前
|
Arthas 监控 Java
JVM进阶调优系列(9)大厂面试官:内存溢出几种?能否现场演示一下?| 面试就那点事
本文介绍了JVM内存溢出(OOM)的四种类型:堆内存、栈内存、元数据区和直接内存溢出。每种类型通过示例代码演示了如何触发OOM,并分析了其原因。文章还提供了如何使用JVM命令工具(如jmap、jhat、GCeasy、Arthas等)分析和定位内存溢出问题的方法。最后,强调了合理设置JVM参数和及时回收内存的重要性。
|
9天前
|
Java Linux Windows
JVM内存
首先JVM内存限制于实际的最大物理内存,假设物理内存无限大的话,JVM内存的最大值跟操作系统有很大的关系。简单的说就32位处理器虽然可控内存空间有4GB,但是具体的操作系统会给一个限制,这个限制一般是2GB-3GB(一般来说Windows系统下为1.5G-2G,Linux系统下为2G-3G),而64bit以上的处理器就不会有限制。
10 1
下一篇
无影云桌面