【JVM】聊聊垃圾回收之三色标记算法
在垃圾收集器 CMS中存在四个阶段,初始标记、并发标记、重新标记、并发清理。

那么在并发标记中由于没有STW,业务程序和GC程序是并发执行的,那么是如何实现对象的并发标记的。
并发垃圾回收
并发标记其实是一个宏观的过程,仍然需要STW,只不过减少STW的时间。
初始标记:标记GC Roots,并发标记是在应用程序不暂停的情况下,以GC Roots为起点,广度或者深度遍历所有可达对象。因为在这个过程中,应用程序和GC程序是并发执行的,所有很有可能对象的引用关系随时变化。导致并发标记过程出现标记错误。而重新标记的就是为了调整对标记错误的进行修正。并发清理是在应用程序不暂停的情况下,对垃圾对象进行清理
初始、并发、重新标记 三个阶段属于可达性分析,标记环节。
GC垃圾收集器的其实就是在吞吐量和STW之间权衡,为了减少STW对业务的影响,只能利用并发执行。
三色标记算法
三色标记是应用程序还在执行,对象引用关系随时会发生变化,所以引入三色标记算法。
白色对象: 没有被遍历过的对象,在开始遍历时都是白色对象,在经过可达性分析之后,还是白色,那么就是可被回收的对象。
灰色对象: 该对象已经被遍历,但是所引用的对象没有被遍历完。
黑色对象: 对象已经被遍历,所引用的对象已全部被遍历。
核心流程:
1.初始化将GC roots对象设置为灰色,其他对象为白色
2.以GC roots 开始遍历,将可达对象设置为灰色,自己设置为黑色
3.重复执行上述,最后是白色的对象就是不可达对象。
而1就是初始标记阶段,2、3是并发标记阶段。
说白了就是一个游戏,大家成群结对,找到不在队伍中的人员,开始都是一样的颜色,经过标记后,脱离队伍的一定是初始颜色的同学。

漏标和误标
在并发标记的过程,因为应用程序在同步执行,所以可能将存活对象标记为死亡对象称为漏标,将死亡对象标记为存活对象称为误标,后者是不可接受的,前者在下一次GC时会被清理。
误标
如果目前对象标记状态时如下图,那么当objA.fieldB = null ,因为本身A对象已经被标记为黑色,那么B以及B引用的对象都将标记为存活对象。

漏标
如果目前对象标记时上图所以,执行
objA.filedc = objA.fileB.filedC;
objA.fileB.fileC = null;
那么B到C之间的引用会断开,A和C之间建立连接。因为A是黑色对象,不会在遍历A的引用对象,从而出现漏标,将存活对象标记为死亡对象。

增量更新和原始快照
对于误标其实问题不大,大不了下一次在执行GC的时候处理,但是对于漏标就问题很大,会将存活的对象标记为死亡对象。
产生漏标的主要是两点
1.产生了一个新引用,黑色对象到白色对象的引用
2.删除引用:删除灰色对象到白色对象的所有引用
两种解决方案:增量更新和原始快照,增量更新记录新增的引用关系,原始快照记录的是删除的引用关系。CMS使用增量更新,G1使用原始快照。
增量更新
在并发标记中,如果应用程序新增了一个黑色对象对一个白色对象的引用,那么就将这个白色对象记录下来,在并发标记完成之后,重新标记以白色标记的对象,进行可达性分析。这样漏标的对象就会重新标记为黑色对象。
原始快照
增量更新是对新增的,而原始快照针对的是当删除一个白色对象对于灰色对象的引用时,虚拟机会记录这个白色对象,在完成并发标记阶段后,在可达性分析这些白色对象的引用关系。
对于上述不管时什么其实都需要在代码的新增和删除引用的过程进行拦截处理,也叫读写屏障。
虚拟机的记录操作都是通过写屏障实现的。
写屏障
给某个对象的成员变量赋值时,其底层代码大概长这样:
/*** @param field 某对象的成员变量,如 a.b.d* @param new_value 新值,如 null*/void oop_field_store(oop* field, oop new_value) {*field = new_value; // 赋值操作
}
所谓的写屏障,其实就是指在赋值操作前后,加入一些处理(可以参考AOP的概念)
void oop_field_store(oop* field, oop new_value) {pre_write_barrier(field); // 写屏障‐写前操作*field = new_value;post_write_barrier(field, value); // 写屏障‐写后操作
}
写屏障实现SATB
当对象B的成员变量的引用发生变化时,比如引用消失(a.b.d = null),我们可以利用写屏障,将B原来成员变量的引用对象D记录下来:
void pre_write_barrier(oop* field) {oop old_value = *field; // 获取旧值remark_set.add(old_value); // 记录原来的引用对象
}
写屏障实现增量更新
当对象A的成员变量的引用发生变化时,比如新增引用(a.d = d),我们可以利用写屏障,将A新的成员变量引用对象D 记录下来:
void post_write_barrier(oop* field, oop new_value) { remark_set.add(new_value); // 记录新引用的对象
}
读屏障
读屏障是直接针对第一步:D d = a.b.d,当读取成员变量时,一律记录下来:
void pre_load_barrier(oop* field) {oop old_value = *field;remark_set.add(old_value); // 记录读取到的对象
}
CMS:写屏障 + 增量更新
G1,Shenandoah:写屏障 + SATB
ZGC:读屏障
并发清理和新建对象
在最后的阶段,并发清理阶段,其实存活对象可能变成死亡对象,那么只需要在下次GC时进行回收就可以了,那么死亡对象可能变成存活对象嘛,从而导致被清理掉嘛?
因为死亡对象不在有变量可以直接被引用。
** 为什么CMS和G1都使用标记-清除而非标记-整理算法来回收老年代的垃圾对象?**
垃圾回收时间快,减少STW时间。在多次垃圾回收之后进行一次碎片整理有效避免了分配效率问题和空间利用率问题。
小总
本篇主要介绍了垃圾回收算法中CMS中 并发标记阶段中的主要问题,从而引出漏标和误标,而解决漏标的问题主要增量更新和原始引用,而都是通过底层的读写屏障解决的。
相关文章:
【JVM】聊聊垃圾回收之三色标记算法
在垃圾收集器 CMS中存在四个阶段,初始标记、并发标记、重新标记、并发清理。 那么在并发标记中由于没有STW,业务程序和GC程序是并发执行的,那么是如何实现对象的并发标记的。 并发垃圾回收 并发标记其实是一个宏观的过程,仍然需…...
鸿蒙Harmony应用开发—ArkTS声明式开发(基础手势:Image)
Image为图片组件,常用于在应用中显示图片。Image支持加载PixelMap、ResourceStr和DrawableDescriptor类型的数据源,支持png、jpg、jpeg、bmp、svg、webp和gif类型的图片格式。 说明: 该组件从API Version 7开始支持。后续版本如有新增内容&am…...
华为OD面试分享8(2024年)
个人情况: 23毕业,24一战跨考ustc,觉G。 211本,目标院校。 知识储备: 仅限408 用leetcode刷过408排序算法 0项目经验 时间线: 23.12.27 投的简历。当时啥也不会啥也不知道,听入职的同学说…...
Java的堆如何分代的?
前言: java对象一般都是朝生夕死,也有部分对象是一直存在的。两种对象如何都放在一起,进行垃圾回收的时候效率较低。所以通过将不同时期的对象放在不同的内存池中,节省垃圾回收的时间,提高性能。 组成: 新生…...
C# CallerMemberName、CallerFilePath、CallerLineNumber
CallerMemberName:调用某个方法的主方法名称 CallerFilePath:调用某个方法的主方法所在的类文件地址 CallerLineNumber:调用这个方法所在的行号 用这三个附加属性,需要设置默认值。...
Claude3系统解读与使用测评
大家好,我是herosunly。985院校硕士毕业,现担任算法研究员一职,热衷于机器学习算法研究与应用。曾获得阿里云天池比赛第一名,CCF比赛第二名,科大讯飞比赛第三名。拥有多项发明专利。对机器学习和深度学习拥有自己独到的见解。曾经辅导过若干个非计算机专业的学生进入到算法…...
vue3注册全局组件
注册单个全局组件 一.在main.ts中引入注册为全局组件 在main.ts 引入我们的组件跟随在createApp(App) 后面 切记不能放到mount 后面这是一个链式调用用其次调用 component 第一个参数组件名称 第二个参数组件实例 import { createApp } from vue import App from ./App.vue …...
vue 在什么情况下在数据发生改变的时候不会触发视图更新
在 Vue 中,通常数据发生变化时,视图会自动更新。但是,有几种情况可能导致数据变化不会触发视图更新: 1.对象属性的添加或删除: Vue 无法检测到对象属性的添加或删除。因为 Vue 在初始化实例时对属性执行了 getter/se…...
HTML世界之标签Ⅲ
一、dfn 标签 <dfn> 标签是一个短语标签,用来定义一个定义项目。 写法: <dfn></dfn> 二、dialog 标签 <dialog> 标签定义一个对话框、确认框或窗口。 属性 值 描述 open open 规定 dialog 元素是有效的,用户…...
【UE5】游戏框架GamePlay
项目资源文末百度网盘自取 游戏框架 游戏 由 游戏模式(GameMode) 和 游戏状态(GameState) 所组成 加入游戏的 人类玩家 与 玩家控制器(PlayerController) 相关联 玩家控制器允许玩家在游戏中拥有 HUD,这样他们就能在关卡中拥有物理代表 玩家控制器还向玩家提供 …...
用户管理【MySQL】
文章目录 查看用户信息创建用户修改密码删除用户授予权限收回权限 查看用户信息 在名为mysql的数据库中有一个表user维护着 MySQL 的用户信息。 其中: user: 表示该用户的用户名。host: 表示该用户可以从哪个主机登录,localhost…...
Rust教程:How to Rust-变量
本文为第1篇 专栏简介 本专栏是优质Rust技术专栏,推荐精通一门技术栈的蟹友,不建议完全无计算机基础的同学 感谢Rust圣经开源社区的同学,为后来者提供了非常优秀的Rust学习资源 本文使用: 操作系统macOS Sonoma 14 / Apple M…...
TCP/IP超全笔记 - TCP篇
TCP/IP超全笔记 - TCP篇 什么是 TCP TCP(Transmission Control Protocol,传输控制协议)是一种面向连接的、可靠的、基于字节流的传输层通信协议。 面向连接:一对一,先连接,再传输数据可靠交付:…...
MIT 6.858 计算机系统安全讲义 2014 秋季(一)
译者:飞龙 协议:CC BY-NC-SA 4.0 MIT 6.858 计算机系统安全笔记 2014 秋季 2014 年由Nickolai Zeldovich 教授和James Mickens 教授教授授课的 6.858 讲座笔记。这些讲座笔记略有修改,与 6.858 课程网站上发布的内容略有不同。 第1讲&#x…...
mybatis-plus整合spring boot极速入门
使用mybatis-plus整合spring boot,接下来我来操作一番。 一,创建spring boot工程 勾选下面的选项 紧接着,还有springboot和依赖我们需要选。 这样我们就创建好了我们的spring boot,项目。 简化目录结构: 我们发现&a…...
Kafka|处理 Kafka 消息重复的有效措施
文章目录 消息重复场景生产者端Kafka Broker消费者端 如何防止消息重复 消息重复是 Kafka 系统中另一个常见的问题,可能发生在生产者、Broker 或消费者三个方面。下面我们来讨论一些可能导致消息重复的场景以及如何处理。 消息重复场景 生产者端 重试机制导致消息…...
【C++】函数模板和类模板
目录 1.泛型编程 2.函数模板 2.1函数模板的定义格式 2.2函数模板的实例化 2.3函数模板参数的匹配原则 3.类模板 3.1类模板的定义格式 3.2类模板的实例化 3.3模板的分离编译 1.泛型编程 泛型编程:编写与类型无关的通用代码,是代码复用的一种手段…...
Echarts 配置项 series 中的 data 是多维度
文章目录 需求分析 需求 如下图数据格式所示,现要求按照该格式进行绘制折线图 分析 在绘制折线图时,通常我们的 series 中的 data 数据是这样的格式 option {title: {text: Stacked Area Chart},tooltip: {trigger: axis,axisPointer: {type: cross…...
快速了解Redis
Redis是什么? Redis是一个数据库,是一个跨平台的非关系型数据库,Redis完全开源,遵守BSD协议。它通过键值对(Key-Value)的形式存储数据。 与传统数据库不同的是 Redis 的数据是存在内存中的 ,也就是它是内存数据库&am…...
1.2_2 OSI参考模型
文章目录 1.2_2 OSI参考模型一、概述(一)ISO/OSI参考模型是怎么来的?(二)ISO/OSI参考模型(三)ISO/OSI参考模型解释通信过程 二、各层功能及协议(一)应用层(第…...
条件运算符
C中的三目运算符(也称条件运算符,英文:ternary operator)是一种简洁的条件选择语句,语法如下: 条件表达式 ? 表达式1 : 表达式2• 如果“条件表达式”为true,则整个表达式的结果为“表达式1”…...
【JavaSE】绘图与事件入门学习笔记
-Java绘图坐标体系 坐标体系-介绍 坐标原点位于左上角,以像素为单位。 在Java坐标系中,第一个是x坐标,表示当前位置为水平方向,距离坐标原点x个像素;第二个是y坐标,表示当前位置为垂直方向,距离坐标原点y个像素。 坐标体系-像素 …...
Maven 概述、安装、配置、仓库、私服详解
目录 1、Maven 概述 1.1 Maven 的定义 1.2 Maven 解决的问题 1.3 Maven 的核心特性与优势 2、Maven 安装 2.1 下载 Maven 2.2 安装配置 Maven 2.3 测试安装 2.4 修改 Maven 本地仓库的默认路径 3、Maven 配置 3.1 配置本地仓库 3.2 配置 JDK 3.3 IDEA 配置本地 Ma…...
NXP S32K146 T-Box 携手 SD NAND(贴片式TF卡):驱动汽车智能革新的黄金组合
在汽车智能化的汹涌浪潮中,车辆不再仅仅是传统的交通工具,而是逐步演变为高度智能的移动终端。这一转变的核心支撑,来自于车内关键技术的深度融合与协同创新。车载远程信息处理盒(T-Box)方案:NXP S32K146 与…...
【笔记】WSL 中 Rust 安装与测试完整记录
#工作记录 WSL 中 Rust 安装与测试完整记录 1. 运行环境 系统:Ubuntu 24.04 LTS (WSL2)架构:x86_64 (GNU/Linux)Rust 版本:rustc 1.87.0 (2025-05-09)Cargo 版本:cargo 1.87.0 (2025-05-06) 2. 安装 Rust 2.1 使用 Rust 官方安…...
LLMs 系列实操科普(1)
写在前面: 本期内容我们继续 Andrej Karpathy 的《How I use LLMs》讲座内容,原视频时长 ~130 分钟,以实操演示主流的一些 LLMs 的使用,由于涉及到实操,实际上并不适合以文字整理,但还是决定尽量整理一份笔…...
02.运算符
目录 什么是运算符 算术运算符 1.基本四则运算符 2.增量运算符 3.自增/自减运算符 关系运算符 逻辑运算符 &&:逻辑与 ||:逻辑或 !:逻辑非 短路求值 位运算符 按位与&: 按位或 | 按位取反~ …...
Vue 3 + WebSocket 实战:公司通知实时推送功能详解
📢 Vue 3 WebSocket 实战:公司通知实时推送功能详解 📌 收藏 点赞 关注,项目中要用到推送功能时就不怕找不到了! 实时通知是企业系统中常见的功能,比如:管理员发布通知后,所有用户…...
相关类相关的可视化图像总结
目录 一、散点图 二、气泡图 三、相关图 四、热力图 五、二维密度图 六、多模态二维密度图 七、雷达图 八、桑基图 九、总结 一、散点图 特点 通过点的位置展示两个连续变量之间的关系,可直观判断线性相关、非线性相关或无相关关系,点的分布密…...
边缘计算网关提升水产养殖尾水处理的远程运维效率
一、项目背景 随着水产养殖行业的快速发展,养殖尾水的处理成为了一个亟待解决的环保问题。传统的尾水处理方式不仅效率低下,而且难以实现精准监控和管理。为了提升尾水处理的效果和效率,同时降低人力成本,某大型水产养殖企业决定…...
