标记垃圾,有三种色彩:四千长文带你深入了解三色标记算法

news2024/11/26 22:41:50

在这里插入图片描述

🔭 嗨,您好 👋 我是 vnjohn,在互联网企业担任 Java 开发,CSDN 优质创作者
📖 推荐专栏:Spring、MySQL、Nacos、Java,后续其他专栏会持续优化更新迭代
🌲文章所在专栏:JVM
🤔 我当前正在学习微服务领域、云原生领域、消息中间件等架构、原理知识
💬 向我询问任何您想要的东西,ID:vnjohn
🔥觉得博主文章写的还 OK,能够帮助到您的,感谢三连支持博客🙏
😄 代词: vnjohn
⚡ 有趣的事实:音乐、跑步、电影、游戏

目录

  • 前言
  • 可达性分析算法
  • 标记过程
  • 三色标记算法
    • 多标
    • 漏标
    • Compare
  • 总结

前言

回顾 优化内存利用:深入了解垃圾回收算法与回收器 一文,介绍了垃圾回收算法、垃圾收集器(垃圾收集算法是内存回收的方法论,那么垃圾收集器就是内存回收的实践者)

主要谈到了 CMS、G1 这两种垃圾收集器,它们都有一个共同的特征,可支持并发标记,从此文来介绍它们两者在并发标记阶段共同所使用的算法

可达性分析算法

当前主流编程语言的垃圾收集器基本上都是依靠可达性分析算法来判定对象是否存活的,可达性分析算法理论上要求全过程都基于一个能保障一致性的快照才能进行分析,这意味着必须全程冻结用户线程的运行

在 JVM 整个内存结构布局中,堆的大小占比是特别大的,堆越大,存储的对象就越多,对象图结构就越复杂,从而就要标记更多的对象而产生的 STW 时间就会越长

“标记阶段”是所有垃圾收集算法的共同特征,若这个阶段随着堆变大而增加停顿时间,其所有的垃圾收集器都会在这个阶段都会波及到一定影响,若能够削减这部分带来的停顿时间,收益也将会是系统性的提高

标记过程

简要回顾一下 CMS、G1 两者垃圾收集器在进行垃圾回收时所要发生的四个阶段:

  • CMS:初始标记、并发标记、重新标记、并发清除
  • G1:初始标记、并发标记、最终标记、筛选回收

CMS、G1 两者都有并发标记这个阶段,导致了它们两者在用户线程、GC 回收线程同时运行时负载会有所不同,同时也会出现一些引用标记的问题「多标、漏标」

三色标记算法

若要解决或降低用户线程的停顿,首先就会搞清楚为什么必须在一个能保障一致性的快照上同时还能进行对象图的遍历操作

能保障一致性的快照上同时还能进行对象图的遍历操作:指的就是并发标记阶段

在垃圾收集器中实践阶段,引入了 “三色标记” 算法作为辅助工具,把遍历对象图过程中遇到的对象,按照 “是否访问过” 这个条件来标记成三种不同颜色的引用对象

  1. 白色:表示对象尚未被垃圾收集器访问过,在根可达分析刚开始的阶段,所有对象都是白色的,若在标记阶段结束后,仍然是白色的对象,即代表不可达,对象就会被回收 > 处于消亡状态
  2. 黑色:表示对象以及被垃圾收集器访问过,且这个对象关联的所有引用都已经被扫描过;黑色的对象代表已经被扫描过,它是安全存活的,若其他对象引用指向了黑色对象,无须再重新扫描一遍
  3. 灰色:表示对象已经被垃圾收集器访问过,但这个对象上至少存在一个引用(属性对象)还没被扫描过

在这里插入图片描述

初始状态,只有 GC Roots 是黑色的

在这里插入图片描述

标记过程:并发垃圾收集的标记阶段过程中,灰色对象的标记状态不断向前推进,从黑色对象(已完成标记)扩展到白色对象(尚未被访问)灰色对象是黑、白对象之间的分水岭

从根对象逐步向下扫描,相当于就是在对象图上从黑向白推进「灰色对象作为黑、白两者之间的分水岭」过程,从 Serial 系列、Parallel 系列垃圾收集器来看,当出现垃圾收集时,它们的用户线程是处于冻结态的,只有垃圾收集线程是处于工作态的,就不会出现对象图很乱的问题

故而言之,Serial 系列、Parallel 系列收集器无须额外使用三色标记算法去处理,它们采用追踪式垃圾收集算法(标记-复制、标记-清除、标记-整理)处理即可

在这里插入图片描述

标记完成:标记阶段完成,此时黑色对象就是存活的对象,白色对象就是已消亡且可回收对象

可是,当使用了 CMS 或 G1 垃圾收集器(并发垃圾收集器,支持垃圾收集线程、用户线程并发执行)时,这时候情况就不一样了,垃圾收集线程会在对象图结构上进行颜色标记,同时用户线程也在修改引用关系(即修改对象图的结构)这时就会出现两种后果

多标、漏标

多标

多标:将原来消亡的对象错误标记为存活,这不是好事,增加了额外的内存空间浪费,但其实是可以容忍的,只不过产生了一些逃过本次垃圾收集产生的浮动垃圾而已,下次再进行清理即可

在这里插入图片描述

在颜色状态推进的过程中,正在扫描的黑对象引用切断与灰色对象关系(此时应已被标记为消亡态),但此时又有另外一个黑色对象将其标记了(此时又由最初的消亡态变换为存活态)

漏标

漏标:将原来存活的对象错误标记为已消亡,这种情况下就会比较严重,程序会因此发生程序错误,例如:Class Xxx Not Found

当且仅有两个条件同时满足时,会造成漏标问题的产生,即原本应当是黑色对象的被误标记为白色对象

  1. 插入了一条或多条从黑色对象到白色对象的新引用
  2. 删除了所有从灰色对象到白色对象的新引用

因此,要解决在并发标记阶段所造成的漏标问题,只需要破坏这两个条件中的任意一个条件即可,分别产生了以下两种解决方案:增量更新(Increment Update)以及原始快照(Snapshot At The Beginning -> SATB)

我们来看造成漏标问题的第一个条件是如何产生的,如下图:

在这里插入图片描述

结合第一张、第二张图来看,再看上图,在颜色状态推进的过程中,正在扫描的灰色对象引用切断与白色对象的联系,同时原来白色引用的对象又已经跟扫描过的黑对象建立了引用关系

增量更新的方案是破坏了第一个条件,当黑色对象插入新的指向白色对象关系时,就将这个新插入的引用记录下来,等待并发标记阶段结束以后的下一个阶段,再将这些新插入的引用记录,以黑色对象为根,重新扫描一次

CMS 采用的就是增量更新的方式来处理漏标问题,在它的重新标记阶段进行处理,可以简单理解为,一旦黑色对象插入了新的指向白色对象的引用,它就会变为灰色对象

我们来看造成漏标问题的第二个条件是如何产生的,如下图:

在这里插入图片描述

被切断后的对象重新被黑色对象所引用的对象可能是原有引用链中的一部分,由于黑色对象只会扫描一次,这将导致扫描结束后出现两个被黑色对象所引用的对象仍是白色,所以这两个白色对象就会消失,这种情况就很严重了

原始快照的方案就是破坏了第二个条件,当灰色对象要删除指向白色对象的引用关系时,就将这个要删除的引用记录下来,在并发标记阶段后的下一个阶段,再将这些删除的引用关系以灰色对象为根,重新进行一次扫描工作

G1 采用的就是原始快照 SATB 方式来处理漏标问题的,在它的最终标记阶段进行处理,也可以简单理解为,无论引用关系删除与否,都会按照刚开始扫描的那一刻对象图快照记录来进行重新扫描

Compare

增量更新、原始快照方式,无论是对引用关系的插入还是删除,它们的记录操作都是通过写屏障技术来完成的

写屏障技术被用于记录对象的标记状态,写屏障技术一旦有引用关系发生了变化,它都会进行记录,但现有的 CMS、G1 都采用了插入式写屏障技术来进行优化,减少了一些性能上的开销工作

考虑性能的高低以及两者之间的权衡来决定以黑为根还是以灰为根来进行一次重新扫描工作

增量更新:会重新以黑色对象为根进行重新扫描(黑色—>白色),会浪费多一些时间,但考虑到发生漏标问题的情况也不太常见,所以扫描这部分黑色对象自然也就不多
原始快照:可能会把原本要取消引用的对象(灰色—>白色)给错误的标记为存活状态了,从而会产生一些浮动垃圾,也就是前面所说到的多标问题,能够被忽略

总结

该篇博文主要介绍了 CMS、G1 在「并发标记」阶段共同使用到的一种算法:三色标记算法,简要说明了它的多标问题,重点介绍了在使用其算法时会发生的漏标问题,有两种方式可以用来解决这种问题:增量更新、原始快照,CMS 使用的是前者,G1 使用的后者,最后对这两种不同解决方案方式作了一下对比,希望此博文你能够喜欢!

参考文献:《深入理解 Java 虚拟机》周志明著

博文放在 JVM 专栏里,欢迎订阅,会持续更新!

如果觉得博文不错,关注我 vnjohn,后续会有更多实战、源码、架构干货分享!

推荐专栏:Spring、MySQL,订阅一波不再迷路

大家的「关注❤️ + 点赞👍 + 收藏⭐」就是我创作的最大动力!谢谢大家的支持,我们下文见!

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/872156.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

SCSS的基本用法

1、声明变量 $ 声明变量的符号 $ 下面这张图左半部分是scss的语法,右半部分是编译后的css。(整篇文章皆是如此) 2、默认变量 !default sass 的默认变量仅需要在值后面加上 !default 即可。 如果分配给变量的值后面添加了 !default 标志…

jmeter通过BeanShell对接口参数进行MD5和HmacSHA256加密【杭州多测师_王sir】

一、在eclipse里面编写MD5加密算法 package com.Base64;import java.security.MessageDigest; import java.security.NoSuchAlgorithmException;public class Md5Utils {public static String md5(String sourceStr) {String result "";try {MessageDigest md Mess…

教你10分钟内学习如何CSS 设置网页打印时的样式

本文将教您开始为要打印的页面编写CSS所需要的一切提供帮助。 media 规则 If you’ve done any responsive design, you’ll already know about the media rule. As well as different screen sizes, media also lets you target “print” media. Here’s an example: 如果…

【CTF-web】修改请求头(XFF)

题目链接:https://ctf.bugku.com/challenges/detail/id/79.html 随意输入后可以看到需要本地管理员登录,得知这是一道需要修改XFF头的题。 XFF即X-Forwarded-For,该请求标头是一个事实上的用于标识通过代理服务器连接到 web 服务器的客户端的…

腾讯轻量云服务器搭建Node.js开发环境

1.购买腾讯云轻量应用服务器,登录 轻量应用服务器控制台,在 服务器 页面单击 新建。安装运行环境,选择为应用模板 > Web 开发场景 > Node.js 应用模板。 Node.js 是一个事件驱动 I/O 服务端 JavaScript 环境,基于 Chrome V…

分布式文件存储系统-FastDFS

前言:FastDFS 是一个分布式文件存储系统,主要用于存储和管理大规模的文件数据,如图片、视频、文档等,是淘宝前架构师为了存储图片用C语言开发出来的系统。 服务端有两个组件 Tracker Server 与 Storage Server ,对应两…

​API网关类型与区别​

什么是API网关? 在现代软件架构中,API(应用程序编程接口)网关起着重要的作用。它是一个中间层,用于管理和控制应用程序之间的通信。API网关可以提供一些关键功能,如流量控制,安全认证&#xff…

java项目打包运行报异常:Demo-1.0-SNAPSHOT.jar中没有主清单属性

检查后发现pom文件中有错误&#xff0c;需要添加build内容才能恢复正常。 添加下面文件后再次启动恢复正常。 <build><plugins><plugin><groupId>org.springframework.boot</groupId><artifactId>spring-boot-maven-plugin</artifactI…

Docker安装nacos v2.1.1

目录 前言安装nacos安装步骤1&#xff1a;准备1. 安装docker2. 搜索可以使用的镜像。3. 选择合适的redis镜像。3. 也可从docker hub上搜索镜像。 安装步骤2&#xff1a;拉取镜像拉取镜像查看已拉取的镜像 安装步骤3&#xff1a;创建容器创建容器方式1&#xff1a;快速创建容器创…

C语言实现扫雷游戏(附完整代码)

大家好&#xff0c;欢迎来到Mr.kanglong的CSDN博客&#xff0c;这篇博客来讨论一下如何使用C语言实现扫雷游戏&#xff0c;其实扫雷游戏和我之前写的三子棋游戏大体实现框架一样&#xff0c;只是逻辑有所不同。 目录 扫雷游戏介绍 游戏效果 实现代码 game.c game.h test.c 扫…

React学习之路 - 上传代码到GitCode

Git 全局设置 git config --global user.name "AnyaPapa" git config --global user.email "fangtaihongqq.com" 添加SSH密钥 Mac终端输入命令 cd existing_folder git init git remote add origin gitgitcode.net:Java_1710/test.git git add . git com…

msvcr120.dll丢失怎样修复?总结三个dll修复方法

当我遇到msvcr120.dll丢失的问题时&#xff0c;我感到有些困惑和焦虑。因为这个问题会导致我无法运行依赖这个文件的应用程序。msvcr120.dll是运行时库文件的一部分&#xff0c;为应用程序提供了必要的运行时支持。它的丢失会导致应用程序无法正常运行&#xff0c;这让我意识到…

【单片机毕业设计3-基于stm32c8t6的智能家居系统】

【单片机毕业设计3-基于stm32c8t6的智能家居系统】 前言一、功能介绍二、硬件部分三、软件部分总结 前言 &#x1f525;这里是小殷学长&#xff0c;单片机毕业设计篇3 基于stm32的智能家居控制系统 &#x1f9ff;创作不易&#xff0c;拒绝白嫖&#xff08;有需可点击最后链接&a…

[C++] 一篇带你了解C++中动态内存管理,new让大家都有对象

目录 1、C/C内存分布 2.、C语言中动态内存管理方式&#xff1a;malloc、calloc、realloc 3、C内存管理方式 3.1 new/delete操作内置类型 3.2 new和delete操作自定义类型 3.3 malloc与new的异常处理机制 4、operator new与operator delete函数 4.1 operator new与operat…

寻找适合你的在线客服系统?这里有8款推荐(2023年8月更新)

近年来&#xff0c;随着网站交互性的提升&#xff0c;越来越多的企业开始关注并采用在线客服系统&#xff0c;以便更好地与访客互动和沟通。尤其对于外贸网站等需要频繁沟通的行业来说&#xff0c;选择一个合适的在线客服系统显得尤为重要。在这篇文章中&#xff0c;我们将为您…

小白带你学习linux的Redis3.2集群(三十三)

目录 一、Redis主从复制 1、概念 2、作用 3、缺点 4、流程 5、搭建 6、验证 二、Reids哨兵模式 1、概念 2、作用 3、缺点 4、结构 5、搭建 6、验证 三、Redis集群 1、概述 2、原理 3、架构细节 4、选举过程 四、搭建 1、第一步现在外部使用finalshell 9.9…

【Java】ThreadLocal详细解析

ThreadLocal全面解析 前置知识 具有一定的javase和javaweb基础熟悉synchronized关键字熟悉HashMap熟悉 JDBC技术 学习目标 了解ThreadLocal的介绍掌握ThreadLocal的运用场景了解ThreadLocal的内部结构了解ThreadLocal的核心方法源码了解ThreadLocalMap的源码 1. ThreadLoc…

css 实现 html 元素内文字水平垂直居中的N种方法

上一篇博文写了div 中元素居中的N种常用方法&#xff0c;那么单个html元素&#xff1a;div&#xff08;块级元素代表&#xff09;&#xff0c;span&#xff08;行内元素代表&#xff09;中的文字如何水平垂直都居中呢&#xff1f;实现方法如下&#xff1a; 本文例子使用的 html…

机器学习实战5-KMeans聚类算法

文章目录 概述KMeansKMeans参数&接口n_clusters质心inertia模型评估指标轮廓系数Calinski-Harabaz Index 重要参数init & random_state & n_init&#xff1a;初始质心怎么放好?重要参数max_iter & tol&#xff1a;让迭代停下来重要属性与重要接口 概述 聚类 …

微信公众号开发基础

开发文档 https://developers.weixin.qq.com/doc/offiaccount/Basic_Information/Get_access_token.html 一、接入微信公众平台开发 开发者需要按照如下步骤完成&#xff1a; 1.1 填写服务器配置 1.2 验证服务器地址的有效性 开发者提交信息后&#xff0c;微信服务器将发…