【Java虚拟机】三色标记、增量更新、原始快照、记忆集与卡表

news2024/11/18 1:41:36

三色标记、增量更新、原始快照、记忆集与卡表

  • 三色标记
    • 基本原来
    • 错标、漏标
      • 错标
      • 漏标
  • 增量更新
    • 基本原理
    • 写屏障
  • 原始快照
    • 基本原理
    • 为什么G1使用原始快照而不用增量更新。
  • 记忆集与卡表

三色标记

基本原来

三色标记是JVM的垃圾收集器用于标记对象是否存活的一种方法。

三色是指黑、白、灰三种颜色,用这三种颜色记录不同对象的状态。

  • 黑:被标记为黑色的对象,表示该对象已经被GC线程扫描过,并且它所有引用的对象都被扫描过。
  • 白:白色对象是所有对象一开始的颜色,表示该对象还未被GC线程扫描到。
  • 灰:被标记为灰色的对象,表示该对象已经被GC线程扫描过,但是它还有引用的对象没有被扫描到。
    在这里插入图片描述

GC垃圾搜集线程一旦完成遍历,堆内存中要么就是黑色的对象,要么就是白色的对象。如果是黑色的对象,表示它可以通过GC Roots的引用链访问到;如果是白色的对象,表示无法通过GC Roots的引用链访问到。

在这里插入图片描述

那么,此时GC垃圾收集线程就可以把白色对象视作垃圾对象把它们清理掉,释放它们占用的内存空间。

在这里插入图片描述

这样,看起来一切正常,但这是建立在GC进行垃圾收集时用户线程停顿的前提下,也就是有STW的前提下。如果是并发标记,也就是用户线程在GC进行对象图遍历标记存活对象的时候,用户线程继续运行,就会出现错标和漏标的问题。

错标、漏标

错标

错标就是多标,也就是这个对象是个垃圾对象,但是GC把它标记为存活对象。

这种现象一般是由于GC垃圾收集线程已经把一个对象遍历到并标记为灰色或者黑色,然后用户线程把到该对象的引用链断开了。

一个对象被标记为黑色或者灰色,那么该对象就会被认定为存活对象。然后用户线程才把到该对象的引用链断开,此时GC垃圾收集线程是不知道的,GC垃圾收集线程对于已经遍历过的对象,是不会再遍历的,因此该对象就会被当成存活对象被保留下来。但由于引用链已经断开,无法再访问到该对象,因此实际上该对象是个垃圾对象,是应该被回收的,因此这种现象就叫错标或者多标,也就是这个标记是多余的。

在这里插入图片描述

这种问题好解决,只要到下一次垃圾收集,还是会作为白色对象被回收的。

漏标

漏标是指本该被标记为存活的对象,但是GC没有标记,导致该对象被回收,此时用户线程访问该对象,就会发生空指针异常。

这种现象的发生必须满足两个条件:

  1. 一个灰色对象断开了对一个白色对象的引用。
  2. 一个黑色对象又建立对这个白色对象的应用。

在这里插入图片描述

在GC完成剩下的对象的遍历之后,GC就会把它作为白色对象把它回收掉。

在这里插入图片描述
如果用户线程通过这个空指针引用去访问这个被GC回收掉的对象,就会发生空指针异常,这显然是一个很严重的问题。

解决这个问题的方法就是增量更新和原始快照。

增量更新

基本原理

增量更新是CMS用于解决漏标的处理方式。也就是当黑色对象建立对白色对象的引用时,把该黑色对象标记为灰色。

在这里插入图片描述

然后在并发标记阶段结束之后,在重新标记阶段,从新从该灰色对象开始进行深度优先遍历。

在这里插入图片描述

这样,GC就可以把该白色对象标记为黑色,就不会被GC当成垃圾对象被回收。

但是把黑色对象修改为灰色的这个操作如何实现的呢,这肯定不是由GC垃圾收集线程完成的,因为它是不会在并发标记阶段重新扫描已经扫描过的对象的。

写屏障

实际上这个操作是通过写屏障实现,写屏障就是在指针赋值操作前后插入一段额外的逻辑。

在这里插入图片描述

增量更新是在黑色对象建立到白对象引用的之后,把该黑色对象标记为黑色的,因此自然是把写屏障插入到指针赋值操作的后面。

在这里插入图片描述

然后在重新标记阶段,GC就可以从该灰色对象开始,重新进行扫描。

在这里插入图片描述

原始快照

基本原理

G1垃圾收集器解决漏标的办法则是原始快照,原始快照是在灰色对象断开对白色对象的引用时,把被删除的灰色对象到白色对象的引用记录下来,把白色对象修改为灰色。

在这里插入图片描述

这样GC就可在最终标记阶段通过该快照引用继续扫描到该白色对象。

在这里插入图片描述

由于是在灰色对象断开对白色对象的引用前,把该引用作为快照保存下来,因此是在指针赋值操作前插入的写屏障。

在这里插入图片描述

为什么G1使用原始快照而不用增量更新。

我个人觉得,G1之所有使用的是原始快照而不是增量更新,是因为原始快照比起增量更新来说,在最终标记阶段需要扫描的对象更少。

我们根据上面的例子,看看增量更新需要重新扫描的对象:在这里插入图片描述

然后再看看使用原始快照,需要扫描多少个对象:
在这里插入图片描述

可以看到,使用增量更新,需要扫描三个对象。而使用原始快照,只需要重新扫描1个对象。

这个例子只有少量几个对象,如果在真实场景下,对象的数量会非常非常多,这样性能差距就很明显了。并且G1它是面向大内存的垃圾收集器,使用原始快照就会比起使用增量更新来说少扫描很多的对象。

记忆集与卡表

JVM的垃圾收集分为年轻代与老年代两个区域,年轻代的对象朝生夕死,老年代的对象存活的时间较长。因此JVM对年轻代的垃圾收集频率肯定是比老年代的垃圾收集频率要高的。

但是在JVM中存在跨代引用的现象,也就是老年代的对象引用了年轻代的对象,或者是年轻代的对象引用了老年代的对象。但是JVM在进行年轻代的垃圾收集时,只会对年轻代进行扫描,不会扫描老年代,那么如果一个年轻代对象仅存在老年代对象对它的引用时,GC是扫描不到它的,自然就不会被标记为存活对象。

在这里插入图片描述

那么该对象就会被当成垃圾对象回收,当我们通过老年代对象指向该年轻代对象的引用访问该年轻代对象时,就会发生空指针异常。

在这里插入图片描述

因此GC在进行年轻代的垃圾收集时,不能只扫描年轻代的对象,还要扫描老年代中存在跨代引用的对象。如果直接把整个老年代都扫描的话,年轻代GC的性能就太低了,因此JVM定义了一个记忆集(Remember Set),记录非收集区到收集区的引用。比如现在要对年轻代进行垃圾收集,那么此时年轻代区域就是收集区,由于此时不需要对老年代进行垃圾收集,所以老年代就是非收集区。

在这里插入图片描述

记忆集只是一个抽象的概念,不同的Java虚拟机对记忆集有不同的实现,比如Hotspot虚拟机对记忆集的实现就是卡表。

首先Hotspot把内存划分为一小块一小块的区域,这些区域叫做卡页,然后定义一个字节数组CART_TABLE[],这个字节数组就是卡表,卡表中的每一个byte,对应内存中的一个卡页。

在这里插入图片描述

如果老年代中的一个对象引用了年轻代中的一个对象,那么该老年代对象所在的卡页对应在卡表中的那一个byte就会被修改为1,表示该卡页脏了。

在这里插入图片描述

那么当JVM要进行年轻代的垃圾收集时,通过CART_TABLE即可得知老年代区域中哪些卡页是脏页,就会扫描老年代中的脏页,把脏页中的对象加入到GC Roots中。

在这里插入图片描述

这样,被老年代对象引用的年轻代对象也可以被扫描到,就不会被当成垃圾对象被回收了。

这个修改卡表对应byte为脏的动作,也是通过写屏障触发的。

在这里插入图片描述

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

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

相关文章

【opencv】示例-train_HOG.cpp 训练和测试基于支持向量机(SVM)的行人检测器

#include "opencv2/imgproc.hpp" // 包含OpenCV图像处理头文件 #include "opencv2/highgui.hpp" // 包含OpenCV高层GUI(图形用户界面)头文件 #include "opencv2/ml.hpp" // 包含OpenCV机器学习模块头文件 #includ…

软考 - 系统架构设计师 - 质量属性例题 (2)

问题1: 、 问题 2: 系统架构风险:指架构设计中 ,潜在的,存在问题的架构决策所带来的隐患。 敏感点:指为了实现某个质量属性,一个或多个构件所具有的特性 权衡点:指影响多个质量属性…

(一)基于IDEA的JAVA基础15

还是先来说一下: Arrays工具类 Arrays是java.util包提供的工具类 提供了操作数组的方法,如排序,查询等。 如排序(升序)使用sort方法 语法: Arrays.sort(数组名); 还是直接写来看看: public class Test01 { public static void main(String[] args)…

vscode开发 vue3+ts 的 uni-app 微信小程序项目

创建uni-app项目: # 创建用ts开发的uni-app npx degit dcloudio/uni-preset-vue#vite-ts 项目名称 # 创建用js开发的uni-app npx degit dcloudio/uni-preset-vue#vite 项目名称VS Code 配置 为什么选择 VS Code ? HbuilderX 对 TS 类型支持暂不完善VS…

深入理解GCC/G++在CentOS上的应用

文章目录 深入理解GCC/G在CentOS上的应用编译C和C源文件C语言编译C语言编译 编译过程的详解预处理编译汇编链接 链接动态库和静态库静态库和动态库安装静态库 结论 深入理解GCC/G在CentOS上的应用 在前文的基础上,我们已经了解了CentOS的基本特性和如何在其上安装及…

一个基于单片机内存管理-开源模块

概述 此模块是一位大佬写的应用于单片机内存管理模块mem_malloc,这个mem_malloc的使用不会产生内存碎片,可以高效利用单片机ram空间。 源码仓库:GitHub - chenqy2018/mem_malloc mem_malloc介绍 一般单片机的内存都比较小,而且没有MMU,malloc 与free的使用容易造成内存碎…

springboot抑郁症科普知识测试系统ssm-java

本系统设计了二种角色:管理员,用户。通过此系统,管理员可以在线视频、案例展示、、测试试卷、测试试题进行测试。以及在线对测试试卷进行批阅和批量删除,用户可以对自己的测试试卷进行测试,对管理员已经批阅过的试卷可…

【opencv】示例-stereo_calib.cpp 基于OpenCV的立体视觉相机校准的完整示例

// 包含OpenCV库中用于3D校准的相关头文件 #include "opencv2/calib3d.hpp" // 包含OpenCV库中用于图像编码解码的相关头文件 #include "opencv2/imgcodecs.hpp" // 包含OpenCV库中用于GUI操作的相关头文件 #include "opencv2/highgui.hpp" // 包…

在Mac中打开终端的3种方法

在使用Mac时,有时需要深入研究设置,或者完成一些开发人员级的命令行任务。为此,你需要终端应用程序来访问macOS上的命令行。下面是如何启动它。 如何使用聚焦搜索打开终端 也许打开终端最简单、最快的方法是通过聚焦搜索。要启动聚焦搜索&a…

【算法分析与设计】全排列

📝个人主页:五敷有你 🔥系列专栏:算法分析与设计 ⛺️稳中求进,晒太阳 题目 给定一个不含重复数字的整数数组 nums ,返回其 所有可能的全排列 。可以 按任意顺序 返回答案。 示例 示例 1&#xff1…

LoRA微调

论文:LoRA: Low-Rank Adaptation of Large Language Models 实现:microsoft/LoRA: Code for loralib, an implementation of “LoRA: Low-Rank Adaptation of Large Language Models” (github.com) 摘要 自然语言处理的一个重要的开发范式包括&#…

51单片机实验03-单片机定时/计数器实验

目录 一、实验目的 二、实验说明 1、51单片机有两个16位内部计数器/定时器(C/T, Counter/Timer)。 2、模式寄存器TMOD 1) M1M0工作模式控制位; 2) C/T定时器或计数器选择位: 3)GATE定时器/计数器运行…

YOLOv1精读笔记

YOLO系列 摘要1. 将目标检测视为一个回归问题2. 定位准确率不如 SOTA,但背景错误率更低3. 泛化能力强 1.引言1.1 YOLO 速度很快1.2 全局推理 2. Unified Detection2.1 网络设计2.2 训练YOLOv1模型损失函数的选择和其潜在的问题YOLOv1模型如何改进其损失函数来更好地…

关于机器学习/深度学习的一些事-答知乎问(三)

可解释人工智能如何进行创新? (1)解释方法结合。现有的研究较少关注如何将不同的解释方法结合起来,未来可以考虑将不同的 解释方法结合在一起,如正反结合,事实解释侧重于 “为什么”,反事实解释…

回归预测 | Matlab基于RIME-SVR霜冰算法优化支持向量机的数据多输入单输出回归预测

回归预测 | Matlab基于RIME-SVR霜冰算法优化支持向量机的数据多输入单输出回归预测 目录 回归预测 | Matlab基于RIME-SVR霜冰算法优化支持向量机的数据多输入单输出回归预测预测效果基本描述程序设计参考资料 预测效果 基本描述 1.Matlab基于RIME-SVR霜冰算法优化支持向量机的数…

边缘计算【智能+安全检测】系列教程--使用OpenCV+GStreamer实现真正的硬解码,完全消除马赛克

通过现有博客的GST_URL = "rtspsrc location=rtsp://admin:abcd1234@192.168.1.64:554/h264/ch01/main/av_stream latency=150 ! rtph264depay ! avdec_h264 ! videorate ! videoconvert ! appsink sync=false" GStreamer的解码方式解码,大多情况应该存在上图马赛克…

项目实现:Boost搜索引擎

一.项目背景 当前已经有许多上市公司做了搜索引擎,比如说百度,搜狗,360等等,这些项目都是很大的项目,有很高的技术门槛,我们自己实现一个完整的搜索引擎是不可能的,但是我们可以写一个简单的搜…

Springboot+Vue项目-基于Java+MySQL的高校心理教育辅导系统(附源码+演示视频+LW)

大家好!我是程序猿老A,感谢您阅读本文,欢迎一键三连哦。 💞当前专栏:Java毕业设计 精彩专栏推荐👇🏻👇🏻👇🏻 🎀 Python毕业设计 &…

鸿蒙开发快速入门

基本概念 ArkTS 因为ArkTS是基于Type Script扩展而来,是Type Script的超集,所以也可以关注一下Type Script的语法来理解ArkTS的语法 ArkUI HarmonyOS提供了一套UI开发框架,即方舟开发框架(ArkUI框架)。方舟开发框架…

Kafka -基本概念

认识Kafka kafka是一个多分区、多副本、基于zookeeper协调的分布式消息系统。 扮演角色 消息系统存储系统:把消息持久化到磁盘,相比于其他基于内存存储的系统而言,有效降低了数据丢失的风险。流式处理平台 基本概念 kafka的体系结构&…