JVM 三色标记算法

三色标记算法核心原理

三色标记算法是一种JVM的垃圾标记算法,CMS/G1垃圾回收器就是使用的这种算法,它可以让JVM在不发生或者尽可能短的发生STW(Stop The World)的情况下进行垃圾的标记和清除。

顾名思义,三色标记算法是将Java堆中的对象分为了三种颜色,分别是:

  1. 白色:白色对象代表没有被标记过的对象,在GC标记阶段刚开始的时候所有对象都是白色对象;而在GC标记阶段结束的时候,所有白色对象表示没有被引用的对象(即垃圾)。
  2. 灰色:灰色对象表示该对象已经被标记过了,但是其引用的对象还没有被完全标记,JVM需要遍历其子对象来找到可达对象和垃圾。
  3. 黑色:黑色对象表示该对象及其子对象全部都被标记过了,说明该对象已经完成了标记,JVM无需继续处理它。

在这里插入图片描述
如上图所示,以CMS垃圾回收流程为例展示三色标记算法中每种颜色对应的意义:

  1. 初始状态:初始状态时,GC标记还没开始,此时所有的Java对象都是白色对象,即未标记对象;
  2. 初始标记:在初始标记阶段为了缩短STW时间,只标记了GC Roots直接可达的对象。那么这个过程中标记的GC Roots直接可达的对象就是灰色对象,因为这些对象可能包含子对象还并未被完全标记。
  3. 并发标记:在并发标记阶段GC线程会从灰色对象出发,依次标记其所含的子对象,知道所有子对象都被标记完了之后,这些对象就称为了黑色对象。
    3.1 阶段1:此时GC Roots直达对象A、B、C被标记称黑色,而它们的子对象D、F、G被标记成灰色;
    3.2 阶段2:接着D、F、G对象被标记为黑色,而子对象H被标记成灰色;
    3.3 阶段3:H也被标记成黑色,此时所有对象都被标记成了黑色,对象标记完成;
  4. 垃圾清理:在前面的标记过程中,由于所有的灰色对象都有GC Roots可以到达,所以这些黑色对象都是存活对象,而白色对象则是垃圾,需要被清理。

三色标记算法的优势在于是一种增量型的垃圾标记算法,一步步的标记出整个堆中的所有垃圾而无需长时间的STW,造成系统卡顿。

三色标记算法存在的问题

由于在并发标记阶段,GC线程和用户线程是并发运行的,随时可能发生对象之间引用变化从而导致“多标”和“漏标”的问题。

多标问题
在这里插入图片描述

如上图所示,在并发标记阶段,当对象G已经被标记成灰色对象之后,此时C到G得引用被干掉了。

那么此时,C的子对象G和H应该被标记为白色,因为从GC Roots到他们的引用已经消失了,它们已经成为了垃圾对象。

但是由于G已经被标记成为了灰色对象,所以GC线程并不知道G和H需要被标记为白色,而是继续将这两个对象标记成了黑色对象 。

最终结果导致,G和H这部分对象依旧存活,不会被本轮GC所清理,也就产生了浮动垃圾。

漏标问题
在这里插入图片描述
如上图所示,在并发标记阶段,当G已经被标记成了灰色对象,F已经被标记成为了黑色对象,而此时G->H的引用被断开,但是又新建立了一个F->H的引用。

那么此时,由于F已经被标记成为了黑色,那么F的子对象H就不会被扫描和标记到,因此就产生了“漏标”。这样就会导致H对象一直是白色,最后被当作垃圾被清除,这样直接会影响到程序运行的正确性,因此是绝对要被避免的。

实际上,漏标记只有同时满足以下两个条件才能发生:

  1. 一个或者多个黑色对象重新引用了白色对象,即黑色对象成员变量增加了新的引用;
  2. 灰色对象断开了白色对象的引用(直接或者间接),即灰色对象原来的成员变量引用发生了变化;

在上面的三个步骤当中,我们只需要在任意一步的时候讲被漏标的对象H存储起来,然后作为一个灰色对象放入到一个集合当中。等到并发标记结束重新标记的时候,遍历这个集合再次标记剩余对象就可以解决漏标的问题。

但是,这样一来“重新标记”就需要STW,因为只要有用户线程在执行就有可能会出现新的漏标记的情况发生,导致永远无法完成GC的标记过程。不过好在前面的“并发标记”过程已经将大部分的垃圾标记出来了,所以“重新标记”过程所耗费的时间较低。

所以说三色标记算法也无法完全解决STW问题,只能尽可能缩短STW的时间,从而减少系统的停顿。

如何解决漏标问题?

对于多标问题来说,由于像CMS这类垃圾回收算法本身就会产生浮动垃圾,所以不算特别严重的问题,只需要等到下一次GC再回收即可。

但是漏标问题就相对严重得多,它会错误的回收正常的对象,导致程序错误,因此必须避免漏标的情况发生,下面主要介绍漏标的解决方案。

内存屏障方案

针对漏标问题,JVM 团队采用了读屏障与写屏障的方案。读屏障拦截了第一步,而写屏障用于拦截第二和第三步。它们的目的是在读写操作前后记录漏标对象H。下面是读屏障和写屏障的相关实现:

在这里插入图片描述
这里的读屏障直接针对第一步 ObjectH H = objG.fieldH; ,在读取成员变量之前先记录下来。这种做法是保守但安全的,因为重新引用的前提是获取到该白色对象,此时读屏障发挥了作用。

但是读屏障并不是所有对象的读写操作都会执行,只有在“并发标记”阶段($gc_phase == GC_CONCURRENT_MARK)并且对象未被标记(白色对象,!isMarked(field))的情况下才执行。这保证了读屏障的触发是有条件的,并不会对所有对象的读操作都进行记录。

写屏障——写入之前记录漏标对象H

void oop_field_store(oop* field, oop new_value) { *field = new_value; // 赋值操作
} 

写屏障是在给某个对象的成员变量赋值操作前后进行处理,类似于 Spring AOP 的概念:

void oop_field_store(oop* field, oop new_value) {  pre_write_barrier(field); // 写屏障-写前操作*field = new_value; post_write_barrier(field, value); // 写屏障-写后操作
}

这样的设计在写操作前后加入了相应处理,保证了在写操作时对相关对象的状态进行记录和处理。

写屏障同样是在并发标记阶段执行的。在写操作前后加入了处理,包括写前操作 pre_write_barrier 和写后操作 post_write_barrier。写屏障的触发同样是有条件的,不是所有对象的写操作都会记录。

增量更新(Incremental Update)与原始快照(Snapshot At The Beginning,SATB)方案

增量更新(Incremental Update)
在对象D的成员变量引用发生变化时(例如 objF.fieldH = H;),通过写屏障,将F新的成员变量引用对象H记录下来:

void post_write_barrier(oop* field, oop new_value) {  if ($gc_phase == GC_CONCURRENT_MARK && !isMarked(field)) {remark_set.add(new_value); // 记录新引用的对象}
}

这种做法的思路是不要求保留原始快照,而是针对新增的引用将其记录下来等待遍历,即增量更新。增量更新破坏了漏标的条件一:“一个或多个黑色对象重新引用了白色对象”,从而保证了不会漏标。

原始快照(Snapshot At The Beginning,SATB)
当对象E的成员变量引用发生变化时(例如 objG.fieldH = null;),通过写屏障,将E原来成员变量的引用对象G记录下来:

void pre_write_barrier(oop* field) {oop old_value = *field; // 获取旧值remark_set.add(old_value); // 记录原来的引用对象
}

在原来成员变量引用发生变化之前,记录下原来的引用对象。这种做法的思路是尝试保留开始时的对象图,即原始快照(Snapshot At The Beginning,SATB)。当某个时刻的GC Roots确定后,当时的对象图就已经确定了。如果期间发生变化,则可以记录起来,保证标记依然按照原本的视图来。SATB破坏了漏标的条件二:“灰色对象断开了白色对象的引用(直接或间接的引用)”,从而保证了不会漏标。

主流垃圾回收器的漏标处理方案

基于可达性分析的GC算法,尤其是在并发标记的情境下,各种垃圾收集器采用了不同的漏标处理方案。在Java HotSpot VM中,具体的处理方式如下:

  1. CMS(Concurrent Mark-Sweep)——****写屏障 + 增量更新: 在并发标记阶段,CMS采用写屏障机制,通过在对象引用发生变化时进行增量更新,将新的引用记录下来。这有助于防止漏标。增量更新相较于其他方案可能会引入更多的浮动垃圾,但在重新标记阶段无需深度扫描已被删除引用的对象。

  2. G1(Garbage-First)——****写屏障 + 原始快照: G1在并发标记时采用写屏障,并选择了原始快照的方式。这意味着在对象引用发生变化时,将原始引用记录下来。相较于增量更新,原始快照在重新标记阶段可能会更高效,因为不需要深度扫描已被删除引用的对象。这对于G1来说是一个合适的选择,因为它的对象分布在不同的区域,而不像CMS一样集中在一个老年代区域。

  3. Shenandoah——****写屏障 + 原始快照:类似于G1,Shenandoah在并发标记时采用写屏障,并选择了原始快照的方式。这种设计可以提高效率,因为在重新标记阶段不需要深度扫描已被删除引用的对象。

  4. ZGC(Z Garbage Collector)——****读屏障 + 染色指针:ZGC采用了染色指针技术,通过读屏障来处理并发标记。这种设计可以显著减少内存屏障的使用数量,特别是写屏障。染色指针直接在指针中维护引用变动的信息,避免了一些记录操作,对性能有显著的帮助。

这些选择基于不同垃圾收集器的特点和设计目标,以在并发标记过程中尽可能降低对应用程序的影响,并提高垃圾回收的效率

总结

三色标记算法是一种用于JVM垃圾回收的增量式标记算法,它将Java堆中的对象划分为白色、灰色和黑色三种颜色,分别表示未标记对象、部分标记对象和已完全标记对象。这算法被广泛应用于CMS(Concurrent Mark-Sweep)和G1(Garbage-First)等垃圾回收器中,以在GC标记和清理阶段尽量减少Stop-The-World(STW)的时间,提高系统的响应性。

总体而言,三色标记算法通过增量标记的方式,尽量避免全局性的STW,提高了垃圾回收的并发性,但也需要处理漏标问题。各种垃圾回收器在实际应用中选择不同的方案来平衡性能和准确性的要求。

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

如若内容造成侵权/违法违规/事实不符,请联系长河编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

Linux(Centos7)OpenSSH漏洞修复,升级最新openssh-9.7p1

OpenSSH更新 一、OpenSSH漏洞二、安装zlib三、安装OpenSSL四、安装OpenSSH 一、OpenSSH漏洞 服务器被扫描出了漏洞需要修复,准备升级为最新openssh服务 1. 使用ssh -v查看本机ssh服务版本号 ssh -V虚拟机为OpenSSH7.4p1,现在准备升级为OpenSSH9.7p1…

springboot小型超市商品展销系统-计算机毕业设计源码01635

摘 要 科技进步的飞速发展引起人们日常生活的巨大变化,电子信息技术的飞速发展使得电子信息技术的各个领域的应用水平得到普及和应用。信息时代的到来已成为不可阻挡的时尚潮流,人类发展的历史正进入一个新时代。在现实运用中,应用软件的工作…

“暗蚊”黑产团伙通过国内下载站传播Mac远控木马攻击活动分析

黑客&网络安全如何 1 概述 近期,安天CERT发现一组利用非官方软件下载站进行投毒和攻击下游用户案例,并深入分析了攻击者在网管运维工具上捆绑植入macOS平台远控木马,利用国内非官方下载站发布,以此取得政企机构内部…

nvm 报错https://npm.taobao.org/mirrors/node/index.json 淘宝镜像更换

文章目录 一、问题背景二、解决问题1. 获取配置文件的位置2. 修改配置文件中的镜像源配置3. 修改 npm 镜像源 一、问题背景 使用nvm的时候报错: Could not retrieve https://npm.taobao.org/mirrors/node/index.json. 由于淘宝的镜像域名更换,npm.taobao.org 域名…

【PowerDesigner】创建和管理CDM之新建实体

目录 🌊1. PowerDesigner简介 🌍1.1 常用模型文件 🌍1.2 PowerDesigner使用环境 🌊2. 创建和管理CDM 🌍​​​​​​2.1 新建CDM 🌍2.2 新建实体 🌊3. 研究心得 🌊1. PowerDe…

qss实现登录界面美化

qss实现登录界面美化 #include "widget.h" #include "ui_widget.h"Widget::Widget(QWidget *parent): QWidget(parent), ui(new Ui::Widget) {ui->setupUi(this);// 去掉头部this->setWindowFlag(Qt::FramelessWindowHint);// 去掉空白部分th…

元数据:数据的罗塞塔石碑

在大数据时代,我们每天都在生成和处理海量数据。但数据本身,如果没有适当的上下文和描述,就像是一堆没有翻译的古老文字。这就是元数据发挥作用的地方——它是大数据世界的罗塞塔石碑,为我们提供了理解和利用数据的关键。 文章目录…

期末考试老师怎样发成绩

期末成绩的公布,总是让老师感到焦虑。成绩,这一张张的数字,承载着学生一学期的努力,也牵动着家长们的心。 传统的成绩公布方式,写成绩条让学生带回家,或是通过私发家长的方式,都存在一定的弊端。…

记录清除挖矿病毒 solrd 过程

1、发现solrd病毒 端午节期间,kafka 服务器被黑客攻击了,植入了挖矿病毒 solrd,这个病毒很聪明,内存,CPU并没有异常升高,以致于上班第一天完全没有察觉。 上班第一天 正常登录服务器查看 flink ,消费kafka…

云和运维(SRE)的半生缘-深读实证02

这个标题不算太夸张,云计算和很多IT岗位都有缘,但是和运维(SRE)岗位的缘分最深。 “深读实证”系列文章都会结合一些外部事件,点明分析《云计算行业进阶指南》书中的内容。本次分享介绍了下列内容: 我以运维…

ctfshow web 单身杯

web签到 <?phperror_reporting(0); highlight_file(__FILE__);$file $_POST[file];if(isset($file)){if(strrev($file)$file){ //翻转函数include $file;}}要进行反转并且包含文件用data协议 自己写不好写可以用函数帮你翻转 <?php $adata:text/plain,<?eval(…

Cisco Packet Tracer实验(五)不同vlan间的通信简单配置

1&#xff0e;单臂路由(图) 环境&#xff1a;一台路由器&#xff0c;一台二层交换机&#xff0c;两台pc机 单臂路由&#xff08;Single Arm Routing&#xff09;是指在网络架构中&#xff0c;只有一个物理接口&#xff08;单臂&#xff09;连接到路由器三层交换机&#xff0c;而…

大数据分析-二手车用户数据可视化分析

项目背景 在当今的大数据时代&#xff0c;数据可视化扮演着至关重要的角色。随着信息的爆炸式增长&#xff0c;我们面临着前所未有的数据挑战。这些数据可能来自社交媒体、商业交易、科学研究、医疗记录等各个领域&#xff0c;它们庞大而复杂&#xff0c;难以通过传统的数据处…

【漏洞复现】飞企互联-FE企业运营管理平台 treeXml.jsp SQL注入漏洞

0x01 产品简介 飞企互联-FE企业运营管理平台是一个基于云计算、智能化、大数据、物联网、移动互联网等技术支撑的云工作台。这个平台可以连接人、链接端、联通内外&#xff0c;支持企业B2B、C2B与020等核心需求&#xff0c;为不同行业客户的互联网转型提供支持。其特色在于提供…

eclipse如何导入springboot项目

打开eclipse 找到你的springboot项目 点击finish即可 test02就已经导入进去了 配置一下maven 在将那个springboot项目刷新一下即可 运行成功

怎么把网页上的接口信息导入postman

第一步 打开f12&#xff0c;右键选中需要的接口。选择copy-copy as cURL 第二步 打开postman&#xff0c;选择"Raw Text"&#xff0c; 把刚才复制的curl粘贴到空白位置&#xff0c;点击Continue - 最后的效果。导入的接口自带cookie&#xff0c;不用再输入cookie&a…

服务器----阿里云服务器重启或关机,远程连接进不去,个人博客无法打开

问题描述 在使用阿里云免费的新加坡服务器时&#xff0c;发现重启或者是关机在开服务器后&#xff0c;就会出现远程连接不上、个人博客访问不了等问题 解决方法 进入救援模式连接主机&#xff0c;用户名是root&#xff0c;密码是自己设置的 点击访问博客查看更多内容

【Linux】进程_7

文章目录 五、进程8. 进程地址空间9. 进程终止10. 进程等待 未完待续 五、进程 8. 进程地址空间 我们上节知道了进程地址空间是根据页表来使虚拟地址转换成内存中的物理地址&#xff0c;那这种 地址空间 页表 的机制有什么好处呢&#xff1f;①这种机制可以将物理内存从无序…

Luma AI如何注册:文生视频领域的新星

文章目录 Luma AI如何注册&#xff1a;文生视频领域的新星一、Luma 注册方式二、Luma 的效果三、Luma 的优势四、Luma 的功能总结 Luma AI如何注册&#xff1a;文生视频领域的新星 近年来&#xff0c;Luma AI 凭借其在文生视频领域的创新技术&#xff0c;逐渐成为行业的新星。…

python文件操作、文件操作、读写文件、写模式

with读取文件数据内容 with open(filepath,mode,encoding) as file:#具体操作,例如&#xff1a;print(file.read())#查看文件所有的内容。 with&#xff1a;Python中的一个上下文管理器&#xff0c;用于简化资源的管理和释放。它可以用于任意需要进行资源分配和释放的情境…