JVM 三色标记算法

news2024/10/7 19:19:18

在这里插入图片描述

我们要进行垃圾回收,就需要弄明白哪些对象是需要回收的,哪些对象是不需要回收的。针对这个问题,其实业界已经有几种常见的解决方法了。

第一种是计数法

第一种是计数法,就是每个对象都有一个计数器,被引用了加一,移除引用减一。但这种方法比较麻烦,而且也会有循环依赖的问题,因此并不被广泛使用。第二种是根可达算法,即以 GCRoots 为基础去扫描整个引用链,从而找到所有的可达对象,那剩下的其他对象就是不可达的垃圾对象了。

根可达算法

现在被广泛使用的是第二种算法,即根可达算法。

那怎么去实现根可达算法呢?

标记 - 清除

最简单的一种实现方案是:从 GCRoots 节点开始,使用「标记 - 清除」算法去实现。

这种实现方案分为两个阶段,分别是:标记阶段、清除阶段。在标记阶段,它从 GCRoots 节点开始扫描整个引用链,找到所有可达的对象。在清除阶段,扫描整个引用链的不可达对象,然后将垃圾对象清除掉。整个算法实现过程如下图所示。
在这里插入图片描述
但这种方式有一个很大的缺点:整个过程必须「Stop the World」。这就导致整个应用程序必须停止,不能做任何改变,这是非常不友好的。 CMS 回收器出现之前的所有回收器,都是用这种方式实现的,因此 GC 停顿时间都比轿长。

三色标记算法

为了解决上面「标记 - 清除」算法的问题,于是就出现了「三色标记算法」!

三色标记算法指的是将所有对象分为白色、黑色和灰色三种类型。黑色表示从 GCRoots 开始,已扫描过它全部引用的对象,灰色指的是扫描过对象本身,还没完全扫描过它全部引用的对象,白色指的是还没扫描过的对象。

黑色:代表该对象以及该对象下的属性全部被标记过了。(程序需要用到的对象,不应该被回收)
灰色:对象被标记了,但是该对象下的属性未被完全标记。(需要在该对象中寻找垃圾)
白色:对象未被标记(需要被清除的垃圾)

在这里插入图片描述
但仅仅将对象划分成三个颜色还不够,真正关键的是:实现根可达算法的时候,将整个过程拆分成了初始标记、并发标记、重新标记、并发清除四个阶段。

  • 初始标记阶段,指的是标记 GCRoots 直接引用的节点,将它们标记为灰色,这个阶段需要 「Stop the World」。
  • 并发标记阶段,指的是从灰色节点开始,去扫描整个引用链,然后将它们标记为黑色,这个阶段不需要「Stop the World」。
  • 重新标记阶段,指的是去校正并发标记阶段的错误,这个阶段需要「Stop the World」。
  • 并发清除,指的是将已经确定为垃圾的对象清除掉,这个阶段不需要「Stop the World」。

对比一下「四阶段拆分」和「一段式」的实现方式,我们可以看出:通过将最耗时的引用链扫描剥离出来作为并发标记阶段,将其与用户线程并发执行,从而极大地降低了 GC 停顿时间。 但 GC 线程与用户线程并发执行,会带来新的问题:对象引用关系可能会发生变化,有可能发生多标和漏标问题。

多标与漏标问题

多标问题指的是原本应该回收的对象,被多余地标记为黑色存活对象,从而导致该垃圾对象没有被回收。 多标问题会出现,是因为在并发标记阶段,有可能之前已经被标记为存活的对象,其引用被删除,从而变成了不可达对象。例如下图中,假设我们现在遍历到了节点 E,此时应用执行了 objD.fieldE = null;。那么此刻之后,对象 E、F、G 应该是被回收的。但因为节点 E 已经是灰色的,那么 E、F、G 节点都会被标记为存活的黑色状态,并不会被回收。

在这里插入图片描述
多标问题会导致内存产生浮动垃圾,但好在其可以再下次 GC 的时候被回收,因此问题还不算很严重。

漏标问题指的是原本应该被标记为存活的对象,被遗漏标记为黑色,从而导致该垃圾对象被错误回收。 例如下图中,假设我们现在遍历到了节点 E,此时应用执行如下代码。这时候因为 E 对象没有引用了 G 对象,因此扫描 E 对象的时候并不会将 G 对象标记为黑色存活状态。但由于用户线程的 D 对象引用了 G 对象,这时候 G 对象应该是存活的,应该标记为黑色。但由于 D 对象已经被扫描过了,不会再次扫描,因此 G 对象就被漏标了。

var G = objE.fieldG; objE.fieldG = null; // 灰色E 断开引用 白色G
objD.fieldG = G; // 黑色D 引用 白色G

在这里插入图片描述
漏标问题就非常严重了,其会导致存活对象被回收,会严重影响程序功能。

那么我们的垃圾回收器是怎么解决这个问题的呢?

答案是:增加一个「重新标记」阶段。无论是在 CMS 回收器还是 G1 回收器,它们都在并发标记阶段之后,新增了一个「重新标记」阶段来校正「并发标记」阶段出现的问题。 只是对于 CMS 回收器和 G1 回收器来说,它们解决的原理不同罢了。

漏标解决方案

正如前面所说,三色标记算法会造成漏标和多标问题。但多标问题相对不是那么严重,而漏标问题才是最严重的。我们经过分析可以知道,漏标问题要发生需要满足如下两个充要条件:

  1. 有至少一个黑色对象在自己被标记之后指向了这个白色对象
  2. 所有的灰色对象在自己引用扫描完成之前删除了对白色对象的引用

只有当上面两个条件都满足,三色标记算法才会发生漏标的问题。换言之,如果我们破坏任何一个条件,这个白色对象就不会被漏标。这其实就产生了两种方式,分别是:增量更新、原始快照。CMS 回收器使用的增量更新方案,G1 采用的是原始快照方案。

CMS 解决方案

CMS 回收器采用的是增量更新方案,即破坏第一个条件:「有至少一个黑色对象在自己被标记之后指向了这个白色对象」

既然有黑色对象在自己标记后,又重新指向了白色对象。那么我就把这个黑色对象的引用记录下来,在后续「重新标记」阶段再以这个黑色对象为跟,对其引用进行重新扫描。通过这种方式,被黑色对象引用的白色对象就会变成灰色,从而变为存活状态。

这种方式有个缺点,就是会重新扫描新增的这部分黑色对象,会浪费多一些时间。但是这段时间相对于并发标记整个链路的扫描,还是小巫见大巫,毕竟真正发生引用变化的黑色对象是比较少的

G1 解决方案

G1 回收器采用的是原始快照的方案,即破坏第二个条件:「所有的灰色对象在自己引用扫描完成之前删除了对白色对象的引用」。

既然灰色对象在扫描完成后删除了对白色对象的引用,那么我是否能在灰色对象取消引用之前,先将灰色对象引用的白色对象记录下来。随后在「重新标记」阶段再以白色对象为根,对它的引用进行扫描,从而避免了漏标的问题。通过这种方式,原本漏标的对象就会被重新扫描变成灰色,从而变为存活状态。

这种方式有个缺点,就是会产生浮动垃圾。 因为当用户线程取消引用的时候,有可能是真的取消引用,对应的对象是真的要回收掉的。这时候我们通过这种方式,就会把本该回收的对象又复活了,从而导致出现浮动垃圾。但相对于本该存活的对象被回收,这个代码还是可以接受的,毕竟在下次 GC 的时候就可以回收了。

对于 CMS 和 G1 这两种处理方案哪种更好,很多资料说的是 G1 这种解决方案更好。 原因是其觉得 G1 这种方式产生了一些浮动垃圾,但节省了一些时间。但我对比了一下发现:CMS 和 G1 都需要重新对某些元素进行引用链扫描。从这点看来,好像差别不大。有弄懂的朋友可以评论区留言讨论讨论。

总结

看完了整篇文章,我们试图来回答一些问题。

三色标记算法是什么? 三色标记算法是根可达算法的一种实现方案,其目的是为了找出所有可达对象。

为什么要有三色标记算法? 因为传统的「标记 - 清除」算法效率太低,于是采用三色标记算法通过将对象分成白色、黑色、灰色,以及将整个过程拆分成「初始标记、并发标记、重新标记、并发清除」4 个过程,从而降低 GC 停顿时间。

三色标记算法有什么缺陷? 三色标记算法会产生多标和漏标问题,其中漏标问题最严重。漏标问题会导致本该存活的对象被回收,从而导致严重的程序问题。

漏标有什么解决方案? 漏标有两种解决方案,分别是:增量更新和原始快照方式。CMS 回收器采用了增量更新方式,G1 回收器采用了原始快照方式。

漏标哪种解决方案最好? 江湖传闻 G1 回收器的原始快照方式效率高,但没有确切的理论证明,且听且珍惜。

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

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

相关文章

4.2 x64dbg 针对PE文件的扫描

通过运用LyScript插件并配合pefile模块,即可实现对特定PE文件的扫描功能,例如载入PE程序到内存,验证PE启用的保护方式,计算PE节区内存特征,文件FOA与内存VA转换等功能的实现,首先简单介绍一下pefile模块。 …

uuid-golang中的使用---借鉴使用官网的办法--推荐

写在最前面的话,golang因为是国外开发的,官网,github都是网速卡或者不能使用的,这个时候可以使用国内的,搜索软件包或者下载 https://gitee.com/ 如果可以使用的话,建议从下面两个网站使用, …

Petronas 使用 SAP EWM 的 Liquid UI 离线将运营效率提高了 70%

背景 Petroliam Nasional Berhad(也称为“Petronas”)总部位于马来西亚,是一家充满活力的国际能源公司,业务遍及100多个国家,在各种石油相关活动方面拥有30多年的经验。马来西亚国家石油公司生产在道德和可持续方面推…

数据结构【树】

数据结构与算法之树结构 树的定义树的基本术语树结构和线性结构的比较树的应用 树的定义 树是一种非线性的数据结构,它是一个包含n(n>1)个节点,(n-1)条边的有穷集合。树有多种表现形式,把它叫做“树”是因为它看起来像一个倒挂的树&#…

redis主从(windows版本)

1. 下载redis 1.1、Github下载地址:Releases microsoftarchive/redis GitHub 1.2、百度网盘下载地址:Redis-x64-3.2.100.zip 密码:kdfq 1.3、也可以自行从其它地方下载 2.配置redis主,设置服务,然后启动 端口…

【Vue3】学习笔记-Composition API 的优势

1.Options API 存在的问题 使用传统OptionsAPI中(配置型API),新增或者修改一个需求,就需要分别在data,methods,computed里修改 。 这张图告诉我们,我们在v2的时候功能放到配置中。它想告诉我们所有的功能都拆散了。 …

0基础学习VR全景平台篇 第58篇:高级功能-AI人像合成

功能位置示意 一、本功能将用在哪里? AI人像合成是蛙色VR商业级方案中,重要的裂变推广功能之一; 选取对应照片,通过后台生成实现个人与场景的合影留念,一键转发分享快速传播裂变。 观者者使用本功能时,将…

基于OpenCV 和深度学习实现微笑检测-附免费源码

文末提供免费的源代码下载链接 我们将使用 SMILES 数据集来训练我们的卷积神经网络。一旦我们的模型训练完毕,我们将按照与上一个教程中相同的步骤来检测图像和视频中的微笑: 我们将使用 Haar 级联来检测图像中的人脸。从图像中提取人脸区域。将面部区域传递给我们的网络进行…

Spring Boot 中的 JPA 是什么,如何使用

Spring Boot 中的 JPA 是什么,如何使用 简介 JPA (Java Persistence API) 是一种标准的 ORM (Object Relational Mapping) 规范,用于将 Java 对象映射到关系型数据库中。它提供了一种面向对象的方式来操作数据库,使得开发者可以更加方便地进…

【openGauss5.0企业版一主一备集群】—运维

【openGauss5.0企业版一主一备集群】—运维 🔻 一、openGauss5.0主从集群的维护🔰 1.1 查看单个节点状态🔰 1.2 查看集群所有节点状态🔰 1.3 集群启停🔰 1.4 switchover 主备切换🔰 1.5 模拟主库宕机&#…

Git gui教程---第三篇 Git gui的使用 配置提交信息

配置提交信息 配置好提交的信息,跑路的话,别人也能找到你,哈哈哈。点击“编辑”,选择“选项”,需要关注的地方有三个,一个是全局的版本库,一个是TEST版本库,一个是合并工具。 全局代…

数据库表的创建以及操作

1.创建数据库Market,在Market中创建数据表customers,customers表结构如表4.6所示,按要求进行操作。 (1)创 建数 据库 Market。 (2)创建数据表custo mers, 在c_num字段 上添加主键约束 和自增 约束,在c_birth字段 上添加非空约束。 (3)将c_c…

梯度流(Gradient Flow):探索通往最小值之路

©PaperWeekly 原创 作者 | 苏剑林 单位 | 追一科技 研究方向 | NLP、神经网络 在这篇文章中,我们将探讨一个被称为“梯度流(Gradient Flow)”的概念。简单来说,梯度流是将我们在用梯度下降法中寻找最小值的过程中的各个点连…

【Linux】进程信号之信号的产生

进程信号 一 一、信号入门1、信号的一些特性2、信号的处理方式信号捕捉初识 3、Linux下的信号 二、信号的产生1、通过终端按键产生信号2、调用系统函数向进程发信号a、kill函数b、raise函数c、abort函数 3. 由软件条件产生信号4、硬件异常产生信号 结语 一、信号入门 什么是信号…

yolov7增加AFPN

论文学习:AFPN: Asymptotic Feature Pyramid Network for Object Detection-全新特征融合模块AFPN,完胜PAFPN_athrunsunny的博客-CSDN博客 论文的作者是说在yolo上效果有提升,不过还没有测试,具体还不清楚,把代码撸出来…

开源网安受邀参加2023全球数字经济大会,分享软件安全落地实践经验

近日,2023全球数字经济大会数字安全生态建设专题论坛在京隆重举行。作为2023全球数字经济大会的重要组成部分,本次论坛围绕“数字安全生态建设”这一主题,邀请政府主管部门、行业专家学者、关键信息基础设施运营主体、数字安全企业、数据要素…

第八章 实现商品详情数据异构及静态化

lua操作 设计图详解 1、 普通模式,用户获得redis数据需要经过nginx,php-fpm,php框架,再到redis 2 、直接模式,对于部分高并发请求, 为了提高吞吐率, 有必要砍掉一些环节和应用来实现快速响应,如上图,这里我们将普通模式中的php-fpm和php框架砍掉了。nginx直接从r…

arvr虚拟现实服务商为文旅行业提供全新的交互式营销体验

在AR领域,很多企业都会遇到场景化展示需求的问题,比如需要制作一个宣传片视频、远程协作软件或者产品营销等等,对于这样的场景制作需求,一般都是找像深圳华锐视点这样的第三方AR开发技术公司进行AR场景定制。 AR是将计算机生成的虚…

在萌诺母婴综合体旗下萌诺尊享(新华店)坐月子可以享受哪些服务?

第一次怀孕生孩子内心比较恐惧,尤其担心月子坐不好身体和身材难以恢复。在怀孕期间刷微博看到郑恺苗苗在萌诺尊享(新华店)坐月子的vlog,感觉这里的环境和服务都还不错,主要是看到苗苗在月子期间身材恢复的很快,于是和老公亲自去门…

深入理解计算机系统(一)

信息就是位上下文 #include<stdio.h>int main() {printf("hello,world\n");return 0; } 上面是一个hello程序。它的生命周期是从一个源程序开始的&#xff0c;就是程序员通过编辑器创建并保存的文本文件&#xff0c;文件名是hello.c。&#xff08;源程序实际…