JVM 三色标记算法详解!

在这里插入图片描述

目录

      • 1. 什么是三色标记算法?
        • 三种颜色及其含义:
      • 2. 基础三色标记算法流程 (非并发)
      • 3. 并发场景下的挑战:一致性问题
        • 3.1. 漏标 (Missing Live Object) - 最严重的问题
        • 3.2. 错标 (Floating Garbage) - 不那么严重的问题
      • 4. 屏障机制 (Barrier) - 解决并发问题
        • 4.1. 写屏障 (Write Barrier)
        • 4.2. 读屏障 (Load Barrier)
      • 5. 各GC收集器中的三色标记应用
      • 6. 总结

1. 什么是三色标记算法?

三色标记算法 是一种用于标记存活对象 (Marking Live Objects) 的图遍历算法。它将堆中的所有对象划分为三种颜色,以表示其在可达性分析过程中的不同状态。通过这种颜色标记,垃圾回收器能够区分出哪些对象是存活的(即不应被回收),哪些是死亡的(即可以被回收的)。

该算法是并发垃圾回收器(如CMS、G1、ZGC、Shenandoah等)能够与应用程序线程并行工作的基础。

三种颜色及其含义:
  1. 白色 (White):

    • 表示对象未被访问过
    • 在GC开始时,所有对象都是白色的。
    • 在标记阶段结束时,仍是白色的对象被视为垃圾对象,将被回收。
    • 可以理解为“待处理”或“已死亡”的对象。
  2. 灰色 (Gray):

    • 表示对象已被访问过
    • 但它的一个或多个子对象(它引用的对象)还没有被完全扫描
    • 可以理解为“正在处理中”的对象。
  3. 黑色 (Black):

    • 表示对象已被访问过
    • 并且它的所有子对象(它引用的对象)也全部被扫描过并标记(要么是灰色,要么是黑色)
    • 可以理解为“已处理完成”且“确认存活”的对象。

2. 基础三色标记算法流程 (非并发)

为了理解并发场景下的复杂性,我们首先看一个理想化的、非并发(即应用程序停顿)的三色标记过程:

  1. 初始化: GC开始时,将所有对象都标记为白色
  2. 根集扫描: 从GC Roots(如虚拟机栈、本地方法栈、方法区中的静态变量、常量等)开始,遍历所有直接被GC Roots引用的对象。将这些对象标记为灰色,并放入一个“待处理列表”(通常是一个队列)。
  3. 遍历:
    • 从“待处理列表”中取出一个灰色对象A。
    • 遍历A的所有子对象(字段引用)。
    • 如果子对象B是白色的,则将B标记为灰色,并将其加入“待处理列表”。
    • 当A的所有子对象都被扫描完毕(并相应地被标记为灰色或黑色)后,将对象A标记为黑色
  4. 重复: 重复步骤3,直到“待处理列表”为空。
  5. 结束: 此时,所有黑色对象都是存活的,所有灰色对象最终都会变成黑色(或在某些特殊情况下,如果其子对象有环,它们自身也会被处理成黑色)。最终,所有仍然是白色的对象即为不可达的垃圾,可以被回收。

3. 并发场景下的挑战:一致性问题

当三色标记算法在GC与应用程序线程并发运行时,事情变得复杂。应用程序线程(也称为Mutator)可能会修改对象图,这可能导致两种基本的一致性问题:

3.1. 漏标 (Missing Live Object) - 最严重的问题

定义: 一个明明是存活的对象,在GC标记结束后却被错误地标记为白色,从而被回收。这是最危险的,因为会导致程序错误甚至崩溃。

发生条件: 当以下两个条件同时满足时,就会发生漏标:

  1. 应用程序删除了从“灰色”对象到“白色”对象的引用。 (即A (灰色) 不再引用 C (白色))
  2. 应用程序新增了从“黑色”对象到“白色”对象的引用。 (即B (黑色) 开始引用 C (白色))

举例说明:
在这里插入图片描述

假设有对象A(灰色),B(黑色),C(白色)。

  • 初始状态:GC Roots -> A (灰色已入队),GC Roots -> B (黑色已处理完毕)。A -> C (C是白色)。
  • GC线程正在遍历,B已经是黑色(意味着B及其所有子对象都处理完了)。A是灰色(待处理)。
  • 并发过程:
    1. 应用程序线程执行操作:A.field = null; (删除了 A -> C 的引用)。
    2. 应用程序线程执行操作:B.new_field = C; (新增了 B -> C 的引用)。
  • 结果:
    • A在处理完其子对象后,发现C不再是其子对象,因此C不会通过A的路径被标记。
    • B已经是黑色,按照三色标记原则,黑色对象不会再被扫描,所以C也不会通过B的路径被标记。
    • 最终,C仍然是白色,被误判为垃圾而回收。
3.2. 错标 (Floating Garbage) - 不那么严重的问题

定义: 一个明明是死亡的对象,在GC标记结束后却被错误地标记为黑色,从而没有被回收。

发生条件: 当以下条件满足时,会发生错标:

  • 应用程序删除了所有从“灰色”或“黑色”对象到“白色”对象的引用。 (即一个对象的所有引用链被切断)
  • GC线程在删除操作之前已经访问过该对象,并将其标记为灰色或黑色

举例说明:
在这里插入图片描述

假设对象A(灰色)引用了对象C(白色)。

  • 初始状态:A (灰色已入队),A -> C (C是白色)。
  • 并发过程:
    1. GC线程正在处理A,A将C标记为灰色并加入待处理列表。
    2. 应用程序线程执行操作:A.field = null; (删除了 A -> C 的引用,C变得不可达)。
  • 结果: C已经被GC标记为灰色,最终会被标记为黑色。虽然它已经不可达,但GC不知道,将它作为存活对象保留了下来。这种对象被称为“浮动垃圾”,会在下一次GC周期中被回收。

错标虽然会增加内存占用,但不会导致程序错误,因此通常比漏标更容易接受和处理。


4. 屏障机制 (Barrier) - 解决并发问题

为了解决并发标记中的漏标问题,现代GC引入了屏障机制。屏障是JVM在编译器或运行时,在应用程序代码中插入的一小段代码,用于拦截特定内存操作(读或写),从而记录引用变化信息。

4.1. 写屏障 (Write Barrier)

写屏障在对象引用被修改时触发。它分为:

  1. 增量更新 (Incremental Update) - 基于后写屏障 (Post-write Barrier)

    • 解决思路: 当一个黑色对象A新增了一个对白色对象C的引用时(B.new_field = C;),认为这种引用关系是新增出来,在标记阶段结束时可以重新扫描
    • 工作原理: 当一个黑色对象引用了一个白色对象时,后写屏障会把这个黑色对象重新标记为灰色,让GC重新扫描它的子对象,或者将白色对象C标记为灰色加入待处理队列。
    • 效果: 这种机制确保“黑色对象引用白色对象”的链条不会被遗漏。它只避免了漏标,但可能会造成更多的浮动垃圾。
    • 采用者: CMS GC。
  2. 原始快照 (Snapshot At The Beginning, SATB) - 基于前写屏障 (Pre-write Barrier)

    • 解决思路: 当一个“灰色”对象A删除一个对“白色”对象C的引用时(A.field = null;),将A在GC开始时指向的引用C记录下来。
    • 工作原理: 当一个引用即将从另一个引用中消失时(即修改一个对象的引用字段前),前写屏障会捕捉到被删除的旧引用,将其指向的对象标记为灰色(即放入待处理队列)。
    • 效果: 确保在GC标记开始时所有可达的对象都被标记。这种方式避免了漏标,但会产生更多的浮动垃圾(因为即使对象不可达了,只要GC开始时它可达,就会被标记为存活)。
    • 采用者: G1 GC。
4.2. 读屏障 (Load Barrier)

读屏障在应用程序读取对象引用时触发。它不是直接解决三色标记的漏标问题,而是为了支持更高级的并发机制(如并发对象移动),但在这种机制下,也顺带解决了标记的一致性问题。

  • 解决思路: 应用程序读取引用时,由屏障检查并修正引用状态。
  • 工作原理: 当应用程序读取到一个对象引用时,读屏障会拦截该操作,检查该引用所指向的对象的状态(通过染色指针或转发指针)。如果对象在GC过程中已经被移动,或者其状态需要更新,读屏障会自动将引用修正为新地址或更新其标记状态,然后才将修正后的引用返回给应用程序。
  • 效果: 在并发对象移动的情况下,确保应用程序总是访问到对象最新、正确的地址,从而避免了因对象移动导致的任何不一致,也就间接解决了标记阶段的正确性。
  • 采用者: ZGC (染色指针),Shenandoah GC (Brooks Pointer)。

5. 各GC收集器中的三色标记应用

  • CMS GC (Concurrent Mark-Sweep):
    • 标记算法: 基于三色标记。
    • 屏障: 主要使用增量更新(写屏障)。在并发标记阶段,如果黑色对象引用了白色对象,CMS会通过写屏障将黑色对象置灰,以便重新扫描。这会导致浮动垃圾,但避免了漏标。
    • 暂停: 初始标记和最终标记阶段需要STW。
  • G1 GC (Garbage-First):
    • 标记算法: 基于三色标记。
    • 屏障: 使用SATB(前写屏障)。G1会在并发标记开始时创建堆的逻辑快照,并发标记过程中引用的删除会被记录下来。最终标记时,会处理这些记录。SATB能非常高效地避免漏标,但会产生更多的浮动垃圾
    • 暂停: 初始标记(通常与Young GC绑定)、最终标记(Remark)、混合GC(Mixed GC)阶段需要STW。
  • ZGC (The Z Garbage Collector):
    • 标记算法: 内部仍基于三色标记思想(通过染色指针的Marked0/Marked1位表示)。
    • 屏障: 核心是读屏障染色指针。读屏障会在应用程序读取引用时检查染色指针的状态,如果对象正在被移动或标记状态需要更新,屏障会直接修正引用。
    • 暂停: 初始标记、最终标记和转移开始这几个STW阶段的停顿时间与堆大小无关,极短(亚毫秒级)。
  • Shenandoah GC:
    • 标记算法: 内部基于三色标记。
    • 屏障: 核心是读屏障Brooks Pointer(转发指针)。读屏障在读取引用时,通过Brooks Pointer找到对象的最新地址。
    • 暂停: 初始标记和最终标记这几个STW阶段的停顿时间与堆大小无关,极短(亚毫秒级)。

6. 总结

三色标记算法是理解现代垃圾回收器并发机制的基石。它通过将对象划分为白、灰、黑三种颜色,清晰地定义了GC的标记过程。然而,在并发GC中,由于应用程序线程对对象图的修改,可能导致漏标(最危险)或错标(浮动垃圾)。各种屏障机制(写屏障的增量更新/SATB、读屏障)被发明出来,以保证并发GC过程中的引用修改不会导致漏标,从而确保GC的正确性,并尽可能地减少STW时间。

不同GC收集器选择不同的屏障机制和并发策略,以在吞吐量、停顿时间和内存/CPU开销之间取得平衡。理解这些机制有助于我们更好地诊断GC问题和进行性能调优。

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

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

相关文章

优化神经网络模型以提升R²值至0.99的全面方案

优化神经网络模型以提升R值至0.99的全面方案 1. 问题分析与背景 在深度学习项目中,提升模型的R(决定系数)值至0.99是一个具有挑战性的目标,特别是在处理复杂的时间序列数据时。我们的现有模型结合了LSTM层、自注意力机制和MLP处理…

pgNow:一款免费的PostgreSQL监控与性能诊断工具

pgNow 是一款免费的桌面工具,可以为 PostgreSQL 数据库提供快速集中的监控与性能诊断。 pgNow 不依赖代理,无需任何配置,可以帮助开发者或数据库管理员(DBA)直观地查看数据库的统计信息和关键性能指标。 功能特性 跨平…

深入理解栈与队列——从原理理解到实战应用

目录 一、引言 二、栈(Stack) 2.1 栈的基本概念 2.2 栈的使用 2.3 栈的模拟实现 2.4 栈的实战应用 2.4.1 括号匹配 2.4.2 逆波兰表达式求值 2.4.3 出栈入栈次序匹配 2.4.4 最小栈 三、队列(Queue) 3.1 队列的基本概念 …

用html5写王者荣耀之王者坟墓的游戏2deepseek版

我将为您创建一个王者荣耀英雄坟墓游戏的提词器HTML页面。这个工具将帮助游戏主播或玩家在游戏中快速查看英雄技能、连招顺序等信息。设计思路 创建英雄选择界面实现提词器显示区域,可自定义文本内容添加字体大小、滚动速度控制设计符合王者荣耀风格的UI下面是…

轻阅读:一键解决浏览器无法预览Office文档的实用方案

在日常办公中,通过浏览器直接打开Word、Excel或PPT等文档时,常遇到“需下载后用本地软件打开”的困扰,不仅流程繁琐,还面临格式兼容、设备存储不足等问题。轻阅读(QingYueDu)作为一款轻量级文件在线预览工具…

鸿蒙开发实战项目(六十七):常见组件和容器低代码开发示例(ArkTS)

本文详细代码需订阅下面专栏获取(订阅后私信邮箱+项目名): https://blog.csdn.net/m0_68036862/category_12333038.html 目录 介绍 环境搭建 代码结构解读 创建低代码工程 低代码设计界面布局 实现数据动态渲染 手动创建低代码页面 介绍 本篇Codelab是基于ArkTS语言的…

MySQL学习笔记04-DML-数据的增删改

新增数据--insert样例代码-- DML : 数据操作语言 -- DML : 插入数据 - insert -- 1. 为 emp 表的 username, password, name, gender, phone 字段插入值 insert into emp (username,password,name,gender,phone) values(fei,123456,张飞,1,13888888888);-- 2. 为 emp 表的 所有…

拼多多返利app的服务网格(Service Mesh)实践:Istio在导购系统中的应用

拼多多返利app的服务网格(Service Mesh)实践:Istio在导购系统中的应用 大家好,我是阿可,微赚淘客系统及省赚客APP创始人,是个冬天不穿秋裤,天冷也要风度的程序猿! 在拼多多返利app的…

【RabbitMQ】高级特性:持久性·发送方确认·重试机制·TTL·死信队列·延迟队列·事务·消息分发

RabbitMQ的高级特性还包括我的上篇博客 【RabbitMQ】-----详解RabbitMQ高级特性之消息确认机制-CSDN博客 目录 RabbitMQ高级特性之持久性 持久性 交换机持久化 队列持久化消息持久化 RabbitMQ高级特性之发送方确认机制 发送方确认 添加配置 常量类 声明队列和交换机…

鸿蒙Next ArkWeb网页多媒体开发实战:从基础到高级应用

解锁鸿蒙ArkWeb的强大多媒体能力,让网页视频音频体验媲美原生应用在日常应用开发中,我们经常需要在应用中嵌入网页并展示其中的多媒体内容。鸿蒙HarmonyOS Next的ArkWeb组件提供了强大的网页渲染能力,尤其对网页中的多媒体元素有出色的支持。…

06. Linux进程概念 1

Linux进程概念 冯诺依曼体系 冯诺依曼体系结构(Von Neumann Architecture)是现代计算机设计的奠基石,由数学家约翰冯诺依曼于1945年提出。这一架构彻底改变了早期计算机“硬件即程序”的设计方式,使得计算机可以灵活地运行不同程序…

HTTP标头全解析:保护你的Web应用!

在网络攻击频发的时代,你的Web应用是否像一座没有城墙的城堡,任由XSS、点击劫持和中间人攻击入侵?HTTP标头,这些看似不起眼的响应头,其实是Web安全的隐形守护者。想象一个电商网站,用户数据被窃取&#xff…

rt-linux下__slab_alloc里的另外一处可能睡眠的逻辑

一、背景 在之前的博客 tasklet上下文内存分配触发might_alloc检查及同步回收调用链 里,我们讲了一处内存分配时会引起睡眠的调用链(这个引起睡眠的这个调用链它是在普通linux里也是存在的)。这篇博客里,我们讲一处内存分配路径下…

基于STM32F103C8T6的智能环境监测系统:DHT11温湿度检测与OLED显示实现

引言 你是否曾想实时握身边环境的温湿度变化?无论是居家种植需要精准调控环境,还是实验室存放敏感材料需监控条件,亦或是智能座舱场景下的环境感知,智能环境监测系统正成为连接物理世界与数字管理的重要桥梁。而在众多嵌入式开发…

动态规划在子数组/子串问题

目录 一、最大子数组和(LeetCode 53) 二、环形子数组的最大和(LeetCode 918) 三、乘积最大子数组(LeetCode 152) 四、乘积为正数的最长子数组长度(LeetCode 1567) 五、等差数列…

微信小程序开发笔记(01_小程序基础与配置文件)

ZZHow(ZZHow1024) 参考课程: 【尚硅谷微信小程序开发教程】 [https://www.bilibili.com/video/BV1LF4m1E7kB] 009_文件和目录结构介绍新建页面与调试基础库 一个完整的小程序项目分为两个部分:主体文件、页面文件 主体文件又称全局文件,能够作用于整…

NLP Subword 之 BPE(Byte Pair Encoding) 算法原理

本文将介绍以下内容: 1. BPE 算法核心原理2. BPE 算法流程3. BPE 算法源码实现DemoBPE最早是一种数据压缩算法,由Sennrich等人于2015年引入到NLP领域并很快得到推广。该算法简单有效,因而目前它是最流行的方法。GPT-2和RoBERTa使用的Subword算…

CSS 伪类选择器

伪类选择器(pseudo-class selector)是一种用于选择HTML元素特定状态或特征的关键字,它允许开发者基于文档树之外的信息(如用户交互、元素位置或状态变化)来选择元素并应用样式。伪类选择器以冒号(:)开头,附…

Electron 新特性:2025 版本更新解读

引言:Electron 新特性在 2025 版本更新中的解读核心价值与必要性 在 Electron 框架的持续演进中,新特性的引入是推动桌面开发创新的核心动力,特别是 2025 年的版本更新,更是 Electron 项目从成熟生态到前沿技术的跃进之钥。它不仅…

MyBatis从入门到面试:掌握持久层框架的精髓

MyBatis从入门到面试:掌握持久层框架的精髓 前言 在Java企业级应用开发中,持久层框架的选择至关重要。MyBatis作为一款优秀的半自动化ORM框架,以其灵活的SQL定制能力和良好的性能表现,成为了众多开发者的首选。本文将带你从MyBa…