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

🔭 嗨,您好 👋 我是 vnjohn,在互联网企业担任 Java 开发,CSDN 优质创作者
📖 推荐专栏:Spring、MySQL、Nacos、Java,后续其他专栏会持续优化更新迭代
🌲文章所在专栏:JVM
🤔 我当前正在学习微服务领域、云原生领域、消息中间件等架构、原理知识
💬 向我询问任何您想要的东西,ID:vnjohn
🔥觉得博主文章写的还 OK,能够帮助到您的,感谢三连支持博客🙏
😄 代词: vnjohn
⚡ 有趣的事实:音乐、跑步、电影、游戏
目录
- 前言
- 可达性分析算法
- 标记过程
- 三色标记算法
- 多标
- 漏标
- Compare
- 总结
前言
回顾 优化内存利用:深入了解垃圾回收算法与回收器 一文,介绍了垃圾回收算法、垃圾收集器(垃圾收集算法是内存回收的方法论,那么垃圾收集器就是内存回收的实践者)
主要谈到了 CMS、G1 这两种垃圾收集器,它们都有一个共同的特征,可支持并发标记,从此文来介绍它们两者在并发标记阶段共同所使用的算法
可达性分析算法
当前主流编程语言的垃圾收集器基本上都是依靠可达性分析算法来判定对象是否存活的,可达性分析算法理论上要求全过程都基于一个能保障一致性的快照才能进行分析,这意味着必须全程冻结用户线程的运行
在 JVM 整个内存结构布局中,堆的大小占比是特别大的,堆越大,存储的对象就越多,对象图结构就越复杂,从而就要标记更多的对象而产生的 STW 时间就会越长
“标记阶段”是所有垃圾收集算法的共同特征,若这个阶段随着堆变大而增加停顿时间,其所有的垃圾收集器都会在这个阶段都会波及到一定影响,若能够削减这部分带来的停顿时间,收益也将会是系统性的提高
标记过程
简要回顾一下 CMS、G1 两者垃圾收集器在进行垃圾回收时所要发生的四个阶段:
- CMS:初始标记、并发标记、重新标记、并发清除
- G1:初始标记、并发标记、最终标记、筛选回收
CMS、G1 两者都有并发标记这个阶段,导致了它们两者在用户线程、GC 回收线程同时运行时负载会有所不同,同时也会出现一些引用标记的问题「多标、漏标」
三色标记算法
若要解决或降低用户线程的停顿,首先就会搞清楚为什么必须在一个能保障一致性的快照上同时还能进行对象图的遍历操作?
能保障一致性的快照上同时还能进行对象图的遍历操作:指的就是并发标记阶段
在垃圾收集器中实践阶段,引入了 “三色标记” 算法作为辅助工具,把遍历对象图过程中遇到的对象,按照 “是否访问过” 这个条件来标记成三种不同颜色的引用对象
- 白色:表示对象尚未被垃圾收集器访问过,在根可达分析刚开始的阶段,所有对象都是白色的,若在标记阶段结束后,仍然是白色的对象,即代表不可达,对象就会被回收 > 处于消亡状态
- 黑色:表示对象以及被垃圾收集器访问过,且这个对象关联的所有引用都已经被扫描过;黑色的对象代表已经被扫描过,它是安全存活的,若其他对象引用指向了黑色对象,无须再重新扫描一遍
- 灰色:表示对象已经被垃圾收集器访问过,但这个对象上至少存在一个引用(属性对象)还没被扫描过

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

标记过程:并发垃圾收集的标记阶段过程中,灰色对象的标记状态不断向前推进,从黑色对象(已完成标记)扩展到白色对象(尚未被访问)灰色对象是黑、白对象之间的分水岭
从根对象逐步向下扫描,相当于就是在对象图上从黑向白推进「灰色对象作为黑、白两者之间的分水岭」过程,从 Serial 系列、Parallel 系列垃圾收集器来看,当出现垃圾收集时,它们的用户线程是处于冻结态的,只有垃圾收集线程是处于工作态的,就不会出现对象图很乱的问题
故而言之,Serial 系列、Parallel 系列收集器无须额外使用三色标记算法去处理,它们采用追踪式垃圾收集算法(标记-复制、标记-清除、标记-整理)处理即可

标记完成:标记阶段完成,此时黑色对象就是存活的对象,白色对象就是已消亡且可回收对象
可是,当使用了 CMS 或 G1 垃圾收集器(并发垃圾收集器,支持垃圾收集线程、用户线程并发执行)时,这时候情况就不一样了,垃圾收集线程会在对象图结构上进行颜色标记,同时用户线程也在修改引用关系(即修改对象图的结构)这时就会出现两种后果
多标、漏标
多标
多标:将原来消亡的对象错误标记为存活,这不是好事,增加了额外的内存空间浪费,但其实是可以容忍的,只不过产生了一些逃过本次垃圾收集产生的浮动垃圾而已,下次再进行清理即可

在颜色状态推进的过程中,正在扫描的黑对象引用切断与灰色对象关系(此时应已被标记为消亡态),但此时又有另外一个黑色对象将其标记了(此时又由最初的消亡态变换为存活态)
漏标
漏标:将原来存活的对象错误标记为已消亡,这种情况下就会比较严重,程序会因此发生程序错误,例如:Class Xxx Not Found
当且仅有两个条件同时满足时,会造成漏标问题的产生,即原本应当是黑色对象的被误标记为白色对象
- 插入了一条或多条从黑色对象到白色对象的新引用
- 删除了所有从灰色对象到白色对象的新引用
因此,要解决在并发标记阶段所造成的漏标问题,只需要破坏这两个条件中的任意一个条件即可,分别产生了以下两种解决方案:增量更新(Increment Update)以及原始快照(Snapshot At The Beginning -> SATB)
我们来看造成漏标问题的第一个条件是如何产生的,如下图:

结合第一张、第二张图来看,再看上图,在颜色状态推进的过程中,正在扫描的灰色对象引用切断与白色对象的联系,同时原来白色引用的对象又已经跟扫描过的黑对象建立了引用关系
增量更新的方案是破坏了第一个条件,当黑色对象插入新的指向白色对象关系时,就将这个新插入的引用记录下来,等待并发标记阶段结束以后的下一个阶段,再将这些新插入的引用记录,以黑色对象为根,重新扫描一次
CMS 采用的就是增量更新的方式来处理漏标问题,在它的重新标记阶段进行处理,可以简单理解为,一旦黑色对象插入了新的指向白色对象的引用,它就会变为灰色对象
我们来看造成漏标问题的第二个条件是如何产生的,如下图:

被切断后的对象重新被黑色对象所引用的对象可能是原有引用链中的一部分,由于黑色对象只会扫描一次,这将导致扫描结束后出现两个被黑色对象所引用的对象仍是白色,所以这两个白色对象就会消失,这种情况就很严重了
原始快照的方案就是破坏了第二个条件,当灰色对象要删除指向白色对象的引用关系时,就将这个要删除的引用记录下来,在并发标记阶段后的下一个阶段,再将这些删除的引用关系以灰色对象为根,重新进行一次扫描工作
G1 采用的就是原始快照 SATB 方式来处理漏标问题的,在它的最终标记阶段进行处理,也可以简单理解为,无论引用关系删除与否,都会按照刚开始扫描的那一刻对象图快照记录来进行重新扫描
Compare
增量更新、原始快照方式,无论是对引用关系的插入还是删除,它们的记录操作都是通过写屏障技术来完成的
写屏障技术被用于记录对象的标记状态,写屏障技术一旦有引用关系发生了变化,它都会进行记录,但现有的 CMS、G1 都采用了插入式写屏障技术来进行优化,减少了一些性能上的开销工作
考虑性能的高低以及两者之间的权衡来决定以黑为根还是以灰为根来进行一次重新扫描工作
增量更新:会重新以黑色对象为根进行重新扫描(黑色—>白色),会浪费多一些时间,但考虑到发生漏标问题的情况也不太常见,所以扫描这部分黑色对象自然也就不多
原始快照:可能会把原本要取消引用的对象(灰色—>白色)给错误的标记为存活状态了,从而会产生一些浮动垃圾,也就是前面所说到的多标问题,能够被忽略
总结
该篇博文主要介绍了 CMS、G1 在「并发标记」阶段共同使用到的一种算法:三色标记算法,简要说明了它的多标问题,重点介绍了在使用其算法时会发生的漏标问题,有两种方式可以用来解决这种问题:增量更新、原始快照,CMS 使用的是前者,G1 使用的后者,最后对这两种不同解决方案方式作了一下对比,希望此博文你能够喜欢!
参考文献:《深入理解 Java 虚拟机》周志明著
博文放在 JVM 专栏里,欢迎订阅,会持续更新!
如果觉得博文不错,关注我 vnjohn,后续会有更多实战、源码、架构干货分享!
推荐专栏:Spring、MySQL,订阅一波不再迷路
大家的「关注❤️ + 点赞👍 + 收藏⭐」就是我创作的最大动力!谢谢大家的支持,我们下文见!
相关文章:
标记垃圾,有三种色彩:四千长文带你深入了解三色标记算法
🔭 嗨,您好 👋 我是 vnjohn,在互联网企业担任 Java 开发,CSDN 优质创作者 📖 推荐专栏:Spring、MySQL、Nacos、Java,后续其他专栏会持续优化更新迭代 🌲文章所在专栏&…...
277/300 React+react-router-dom+Vite 二级页面刷新时,白屏问题解决
(一)方案 BrowserRouter 换为 HashRouter (二)代码 import routes from ./routes import {ReactElement, Suspense} from react import {createHashRouter, Navigate} from react-router-dom // 生成路由数据 const generateR…...
如何做线上监控
1、背景 软件的质量是需要全生命周期进行关注的,在生产环境下QA的活动就是测试右移,测试右移最关键的手段就是线上监控,也是至关重要的一个环节,可以通过技术的手段,提前感知到线上问题和风险,先于用户提前发现问题,提升服务可感知性,从而降低客户投诉。 2、通用原则…...
饥荒开服教程——游戏
饥荒开服教程——游戏 1. 开服环境2. 开服步骤2.1 创建集群2.2 安装服务端2.3 上传mod2.4 启动脚本2.5 上传地图2.6 设置访问令牌2.7 修改配置 3. 服务器命令3.1 关闭服务器3.2 回档 记录一些在饥荒联机版开服中遇到过的问题。 参考:3分钟创建你的饥荒联机专属服务…...
查询 npm/yarn 安装依赖的全局路径及路径修改
一、NPM 1.查询 npm 安装依赖的全局路径 npm prefix -g 2. 修改 npm 全局安装位置 npm config set prefix "D:\nodejs\node_modules\npm\node_modules" 3. 修改 npm 全局 cache 位置 npm config set cache "D:\nodejs\node_modules\npm\cache" 4. np…...
掌握Python的X篇_35_用Python为美女打码_图像库Pillow
本篇将会介绍python中的一个图像库Pillow。 文章目录 1. Pillow与PIL的关系2. 调整大小3. 加滤镜4. 剪裁5. 生成验证码 1. Pillow与PIL的关系 我们在网上搜python的图像库的话,可能搜到的时PIL。实际上之前python发展的时候就是PIL,这个库比较好用&…...
SpringBoot 异步、邮件任务
异步任务 创建一个Hello项目 创建一个类AsyncService 异步处理还是非常常用的,比如我们在网站上发送邮件,后台会去发送邮件,此时前台会造成响应不动,直到邮件发送完毕,响应才会成功,所以我们一般会采用多线…...
【LeetCode】45. 跳跃游戏 II - 贪婪算法
目录标题 2023-8-11 09:49:25 45. 跳跃游戏 II 2023-8-11 09:49:25 自己没做出来,废物Orz class Solution {public int jump(int[] nums) {int length nums.length;int end 0;int maxPosition 0;int steps 0;for (int i 0; i < length - 1; i) {maxPosit…...
[C初阶笔记]P1
什么是C语言 1、机器语言(二进制)>汇编语言(助记符)>高级语言(C、C等) 2、c语言擅长底层软件开发(操作系统、驱动程序),并不意味着不能开发其他。 C语言更贴近操作…...
外企面试题
Interview Prepare is there anyone we can talk to for a character reference? yes, I have some teammate can help to provide related working information. why did you leave/quit your last job? I got blocked on my last job. I found I cant learn new things fr…...
【目标检测系列】YOLOV1解读
前言 从R-CNN到Fast-RCNN,之前的目标检测工作都是分成两阶段,先提供位置信息在进行目标分类,精度很高但无法满足实时检测的要求。 而YoLo将目标检测看作回归问题,输入为一张图片,输出为S*S*(5*BC)的三维向量。该向量…...
Sentieon | 每周文献-Multi-omics(多组学)-第九期
多组学系列文章-1 标题(英文): Prediction of axillary lymph node metastasis in triple-negative breast cancer by multi-omics analysis and an integrated model标题(中文): 基于多组学分析和综合模型…...
CSDN竞赛70期
CSDN竞赛70期 CSDN竞赛70期1.小张的手速大比拼分析代码 2.坐公交分析代码 3.三而竭分析代码 4.争风吃醋的豚鼠分析代码 CSDN竞赛70期 1.小张的手速大比拼 在很久很久以前,小张找到了一颗有 N 个节点的有根树 T 。 树上的节点编号在 1 到 N 范围内。 他很快发现树上…...
mac安装vscode 配置git
1、安装vscode 官网地址 下载mac稳定版安装很慢的解决办法 (转自) mac电脑如何解决下载vscode慢的问题 选择谷歌浏览器右上角的3个点,选择下载内容,右键选择复制链接地址,在新窗口粘贴地址, 把地址中的一段替换成下面的vscode.cd…...
UI自动化环境的搭建(python+pycharm+selenium+chrome)
最近在做一些UI自动化的项目,为此从环境搭建来从0到1,希望能够帮助到你,同时也是自我的梳理。将按照如下进行开展: 1、python的下载、安装,python环境变量的配置。 2、pycharm开发工具的下载安装。 3、selenium的安装。…...
AbstractQueuedSynchronizer
目录 AQS是什么AQS什么样内部类成员变量方法public如果不使用AQS会怎样 AQS的应用ReentrantLockSyncNonfairSyncFairSync 其他实现 AQS是什么 AbstractQueuedSynchronizer(AQS)是Java中的一个并发工具,位于java.util.concurrent.locks包中&a…...
谈谈什么是云计算?以及它的应用
作者:Insist-- 个人主页:insist--个人主页 作者会持续更新网络知识和python基础知识,期待你的关注 目录 编辑 一、什么是云计算 二、云计算的优势与劣势? 1、云计算的优势 ①提高资源利用率 ②提升效率 ③降低成本 2、云…...
【BASH】回顾与知识点梳理(十六)
【BASH】回顾与知识点梳理 十六 十六. 十二至十五章知识点总结及练习16.1 总结16.2 练习16.3 简答题 该系列目录 --> 【BASH】回顾与知识点梳理(目录) 十六. 十二至十五章知识点总结及练习 16.1 总结 绝对路径:『一定由根目录 / 写起』…...
docsify gitee 搭建个人博客
docsify & gitee 搭建个人博客 文章目录 docsify & gitee 搭建个人博客1.npm 安装1.1 在Windows上安装npm:1.2 在macOS上安装npm:1.3 linux 安装npm 2. docsify2.1 安装docsify2.2 自定义配置2.2.1 通过修改index.html,定制化开发页面…...
SpringBoot2-Tomcat部署
1.排除内置 Tomcat 在pom.xml文件中的下添加以下代码,用于排除SpringBoot内置Tomcat <dependency><groupId>org.springframework.boot</groupId><artifactId>spring-boot-starter-web</artifactId><exclusions><exclusion&…...
Cesium1.95中高性能加载1500个点
一、基本方式: 图标使用.png比.svg性能要好 <template><div id"cesiumContainer"></div><div class"toolbar"><button id"resetButton">重新生成点</button><span id"countDisplay&qu…...
CentOS下的分布式内存计算Spark环境部署
一、Spark 核心架构与应用场景 1.1 分布式计算引擎的核心优势 Spark 是基于内存的分布式计算框架,相比 MapReduce 具有以下核心优势: 内存计算:数据可常驻内存,迭代计算性能提升 10-100 倍(文档段落:3-79…...
STM32标准库-DMA直接存储器存取
文章目录 一、DMA1.1简介1.2存储器映像1.3DMA框图1.4DMA基本结构1.5DMA请求1.6数据宽度与对齐1.7数据转运DMA1.8ADC扫描模式DMA 二、数据转运DMA2.1接线图2.2代码2.3相关API 一、DMA 1.1简介 DMA(Direct Memory Access)直接存储器存取 DMA可以提供外设…...
零基础设计模式——行为型模式 - 责任链模式
第四部分:行为型模式 - 责任链模式 (Chain of Responsibility Pattern) 欢迎来到行为型模式的学习!行为型模式关注对象之间的职责分配、算法封装和对象间的交互。我们将学习的第一个行为型模式是责任链模式。 核心思想:使多个对象都有机会处…...
SpringTask-03.入门案例
一.入门案例 启动类: package com.sky;import lombok.extern.slf4j.Slf4j; import org.springframework.boot.SpringApplication; import org.springframework.boot.autoconfigure.SpringBootApplication; import org.springframework.cache.annotation.EnableCach…...
CMake控制VS2022项目文件分组
我们可以通过 CMake 控制源文件的组织结构,使它们在 VS 解决方案资源管理器中以“组”(Filter)的形式进行分类展示。 🎯 目标 通过 CMake 脚本将 .cpp、.h 等源文件分组显示在 Visual Studio 2022 的解决方案资源管理器中。 ✅ 支持的方法汇总(共4种) 方法描述是否推荐…...
优选算法第十二讲:队列 + 宽搜 优先级队列
优选算法第十二讲:队列 宽搜 && 优先级队列 1.N叉树的层序遍历2.二叉树的锯齿型层序遍历3.二叉树最大宽度4.在每个树行中找最大值5.优先级队列 -- 最后一块石头的重量6.数据流中的第K大元素7.前K个高频单词8.数据流的中位数 1.N叉树的层序遍历 2.二叉树的锯…...
rnn判断string中第一次出现a的下标
# coding:utf8 import torch import torch.nn as nn import numpy as np import random import json""" 基于pytorch的网络编写 实现一个RNN网络完成多分类任务 判断字符 a 第一次出现在字符串中的位置 """class TorchModel(nn.Module):def __in…...
免费PDF转图片工具
免费PDF转图片工具 一款简单易用的PDF转图片工具,可以将PDF文件快速转换为高质量PNG图片。无需安装复杂的软件,也不需要在线上传文件,保护您的隐私。 工具截图 主要特点 🚀 快速转换:本地转换,无需等待上…...
Redis:现代应用开发的高效内存数据存储利器
一、Redis的起源与发展 Redis最初由意大利程序员Salvatore Sanfilippo在2009年开发,其初衷是为了满足他自己的一个项目需求,即需要一个高性能的键值存储系统来解决传统数据库在高并发场景下的性能瓶颈。随着项目的开源,Redis凭借其简单易用、…...
