JVM 并发 GC - 三色标记

垃圾收集就意味着需要进行可达性算法,但是在执行可达性算法时,当前的 JVM 内部需要保持一个禁止的状态,也就是其他的用户线程不允许进行操作,所有的用户线程需要等到垃圾收集结束后才能开始继续执行,这意味着用户的体验感可能会非常地差:用户可能正在访问某个页面时,JVM 突然开始垃圾回收,如果当前 Java 堆内对象较少,那用户可能会怀疑是自己的网络原因,但是如果已经达到了十分庞大的对象量,用户就会看着加载页面转啊转,甚至弹出页面暂时无法访问。这个时候并发处理就十分重要了。

并发的可达性分析算法 - 三色标记

在三色标记算法中,对象会被标记为三种颜色之一:

  • 白色:表示对象尚未被访问,可能是垃圾。
  • 灰色:表示对象已被访问,但其引用的对象尚未全部访问。
  • 黑色:表示对象及其所有引用的对象都已访问。

但是如果是在并发地进行并发的可达性算法时,用户线程突然对某个将要被删除、并且已经被标记了的对象进行了操作,我们假设所有对象都没有重写 finalize (毕竟 Java 官方不推荐使用),那么这个对象可能刚好被引用,但是下一秒就又被删除了,这样子导致错误。

https://shipilev.net/talks/javazone-Sep2018-shenandoah.pdf

Wilson 在 1994 年在理论上证明了,当且仅当以下两种条件都满足时,会产生"对象消失"问题

  • 赋值器插入了一条或多条从黑色对象到白色对象的引用
  • 赋值器删除了全部从灰色对象到白色对象的直接或间接引用

即:当前对象还未被扫描,当前对象被已经被扫描过并且标记了不会有其他引用对象的对象引用

因此,想要解决并发扫描时对象消失问题,只需要破坏这两种条件的其中一种即可

  • 增量更新
  • 原始快照

增量更新

增量更新破坏的是 "赋值器插入了一条或多条从黑色对象到白色对象的引用" 条件

当对黑色对象插入新的指向白色对象的引用关系时,就将这个新插入的引用记录下来,在并发扫描后,再将这些记录过的引用关系中的黑色对象为根,再重新扫描一次,可以简单理解为:只要黑色对象插入新的指向白色对象的引用,黑色对象就会变成灰色对象

原始快照

当灰色对象要删除指向白色对象的引用关系时,就将这个要删除的引用记录下来,在并发扫描结束之后再将这些记录过的引用关系中的灰色对象为根,重新扫描一次。可以简单理解成:无论引用关系删除与否都会按照刚刚开始扫描的那一刻的图像快照来进行搜索

简单来说,增量更新和原始快照都在一次可达性算法过后对更新过的节点进行扫描以达到不会产生"对象消失"的目的

相关推荐
NAGNIP1 天前
轻松搞懂全连接神经网络结构!
人工智能·算法·面试
NAGNIP1 天前
一文搞懂激活函数!
算法·面试
前端Hardy1 天前
面试官:JS数组的常用方法有哪些?这篇总结让你面试稳了!
javascript·面试
牛奶1 天前
React 底层原理 & 新特性
前端·react.js·面试
牛奶1 天前
ts随笔:面向对象与高级类型
前端·面试·typescript
牛奶1 天前
React 基础理论 & API 使用
前端·react.js·面试
SuperEugene1 天前
从 Vue2 到 Vue3:语法差异与迁移时最容易懵的点
前端·vue.js·面试
SuperEugene1 天前
接口类型管理:从 any 到有组织的 api.d.ts
前端·面试·typescript
牛奶1 天前
ts随笔:基础与类型系统
前端·面试·typescript
用户73992986959721 天前
DeepSeek/GPT-4 落地实战:我如何用 Node.js + AI 手搓一个“面试神器”
面试