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

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

  • 三色标记
    • 基本原来
    • 错标、漏标
      • 错标
      • 漏标
  • 增量更新
    • 基本原理
    • 写屏障
  • 原始快照
    • 基本原理
    • 为什么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.mzph.cn/news/816333.shtml

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

相关文章

Servlet实现常用功能及其他方法

getParameter 获取body或url中指定的key/value值 String classIdreq.getParameter("classId"); getQueryString 获取请求的所有查询参数key,values1 String queryStringreq.getQueryString(); from表单提交 前端通过from表单提交用户名和密码 <!DOCTYPE htm…

Zookeeper和Kafka的部署

目录 一、Zookeeper的基本概念 1. Zookeeper定义 2. Zookeeper工作机制 3. Zookeeper特点 4. Zookeeper数据结构 5. Zookeeper应用场景 5.1 统一命名服务 5.2 统一配置管理 5.3 统一集群管理 5.4 服务器动态上下线 5.5 软负载均衡 6. Zookeeper 选举机制 6.1 第一…

【opencv】示例-text_skewness_correction.cpp 校正文本图像的倾斜度

// 此教程展示了如何矫正文本的偏斜。 // 程序接受一个偏斜的源图像作为输入&#xff0c;并显示非偏斜的文本。#include <opencv2/core.hpp> // 包含OpenCV核心功能的头文件 #include <opencv2/imgcodecs.hpp> // 包含OpenCV图像编解码功能的头文件 #include <o…

每日练习——leetcode402. 移掉 K 位数字和17. 电话号码的字母组合

目录 402. 移掉 K 位数字 题目描述 解题思路 代码实现 17. 电话号码的字母组合 题目描述 解题思路 代码实现 402. 移掉 K 位数字 题目描述 给你一个以字符串表示的非负整数 num 和一个整数 k &#xff0c;移除这个数中的 k 位数字&#xff0c;使得剩下的数字最小。请…

Python杂记--使用asyncio构建HTTP代理服务器

Python杂记--使用asyncio构建HTTP代理服务器 引言基础知识代码实现 引言 本文将介绍 HTTP 代理的基本原理&#xff0c;并带领读者构建一个自己的 HTTP 代理服务器。代码中不会涉及到任何第三方库&#xff0c;全部由 asyncio 实现&#xff0c;性能优秀&#xff0c;安全可靠。 基…

Linux-文件系统理解(磁盘的物理与逻辑结构、什么是inode、OS如何管理磁盘)

一、磁盘 磁盘的物理结构 磁盘的本质是一个机械设备&#xff0c;可以存储大量的二进制信息&#xff0c;是实现数据存储的基础硬件设施&#xff0c;磁盘的盘片类似于光盘&#xff0c;不过盘片的两面都是可读可写可擦除的&#xff0c;每个盘面都有一个磁头&#xff0c;马达可以使…

攻防世界---Web_php_include

1.题目链接 2.补充知识&#xff1a; 3.构造&#xff1a;执行成功 /?pagedata://text/plain,<?php phpinfo()?> 4.构造下面url&#xff0c;得到目录路径 /?pagedata://text/plain,<?php echo $_SERVER[DOCUMENT_ROOT]?> 5构造下面url&#xff0c;读取该路径的…

【网站项目】面向企事业单位的项目申报小程序

&#x1f64a;作者简介&#xff1a;拥有多年开发工作经验&#xff0c;分享技术代码帮助学生学习&#xff0c;独立完成自己的项目或者毕业设计。 代码可以私聊博主获取。&#x1f339;赠送计算机毕业设计600个选题excel文件&#xff0c;帮助大学选题。赠送开题报告模板&#xff…

网络编程【InetAddress , TCP 、UDP 、HTTP 案例】

day38上 网络编程 InetAddress 理解&#xff1a;表示主机类 一个域名 对应 多个IP地址 public static void main(String[] args) throws UnknownHostException {//获取本机的IP地址 // InetAddress localHost InetAddress.getLocalHost(); // System.out.println(localHos…

简单认识Git(dirsearch、githack下载),git泄露(ctfhub)

目录 dirsearch下载地址: githack下载&#xff08;一次不成功可多试几次&#xff09; 一、什么是Git 1.git结构 2.git常用命令及示例 3.Git泄露原理 二、Git泄露 1.Log 2.Stash 3.Index 工具准备&#xff1a;dirsearch、githack dirsearch下载地址: GitHub - mauroso…

搭建Hive 3.x环境(CentOS 9 + Hadoop3.x)

零、资源准备 虚拟机相关&#xff1a; VMware workstation 16&#xff1a;虚拟机 > vmware_177981.zipCentOS Stream 9&#xff1a;虚拟机 > CentOS-Stream-9-latest-x86_64-dvd1.iso JDK jdk1.8&#xff1a;JDK > jdk-8u261-linux-x64.tar.gz Hadoop Hadoop 3.3.6&a…

【Java】内存可见性问题是什么?

文章目录 内存模型内存可见性解决方案volatile 内存模型 什么是JAVA 内存模型&#xff1f; Java Memory Model (JAVA 内存模型&#xff09;是描述线程之间如何通过内存(memory)来进行交互。 具体说来&#xff0c; JVM中存在一个主存区&#xff08;Main Memory或Java Heap Mem…

架构师系列-搜索引擎ElasticSearch(七)- 集群管理之分片

集群健康检查 Elasticsearch 的集群监控信息中包含了许多的统计数据&#xff0c;其中最为重要的一项就是集群健康&#xff0c;它在 status字段中展示为 green&#xff08;所有主分片和副本分片都正常&#xff09;、yellow&#xff08;所有数据可用&#xff0c;有些副本分片尚未…

Collection与数据结构 二叉树(三):二叉树精选OJ例题(下)

1.二叉树的分层遍历 OJ链接 上面这道题是分层式的层序遍历,每一层有哪些结点都很明确,我们先想一想普通的层序遍历怎么做 /*** 层序遍历* param root*/public void levelOrder1(Node root){Queue<Node> queue new LinkedList<>();queue.offer(root);while (!qu…

Spring Boot(二)— 自定义Spring Boot Starter

在Spring Boot中&#xff0c;自定义Spring Boot Starter是一个常见且强大的功能&#xff0c;它允许开发者为特定的功能或库创建自己的自动配置&#xff0c;从而简化集成过程。 1 前置知识 Spring Boot的事件为应用的启动和关闭提供了详细的上下文信息&#xff0c;使得开发者能…

基于表面势的增强型p-GaN HEMT器件模型

来源&#xff1a;电子学报 22年 摘要 为了满足功率电路及系统设计对p-GaN HEMT&#xff08;High Electron Mobility Transistor&#xff09;器件模型的需求&#xff0c;本文建立了一套基于表面势计算方法的增强型p-GaN HEMT器件SPICE&#xff08;Simulation Program with Int…

Golang | Leetcode Golang题解之第27题移除元素

题目&#xff1a; 题解&#xff1a; func removeElement(nums []int, val int) int {left, right : 0, len(nums)for left < right {if nums[left] val {nums[left] nums[right-1]right--} else {left}}return left }

软件杯 深度学习卷积神经网络垃圾分类系统 - 深度学习 神经网络 图像识别 垃圾分类 算法 小程序

文章目录 0 简介1 背景意义2 数据集3 数据探索4 数据增广(数据集补充)5 垃圾图像分类5.1 迁移学习5.1.1 什么是迁移学习&#xff1f;5.1.2 为什么要迁移学习&#xff1f; 5.2 模型选择5.3 训练环境5.3.1 硬件配置5.3.2 软件配置 5.4 训练过程5.5 模型分类效果(PC端) 6 构建垃圾…

Eland上传bge-large-zh-v1.5向量化模型到ElasticSearch中

最近需要做一些向量检索&#xff0c;试试ES 一、准备 系统&#xff1a;MacOS 14.3.1 ElasticSearch&#xff1a;8.13.2 Kibana&#xff1a;8.13.2 本地单机环境&#xff0c;无集群&#xff0c;也不基于Docker BGE是一个常见的文本转向量的模型&#xff0c;在很多大模型RAG应…

数据仓库—维度建模—维度表设计

维度表 维度表(Dimension Table)是数据仓库中描述业务过程中各种维度信息的表,用于提供上下文和描述性信息,以丰富事实数据的分析 维度表是维度建模的灵魂所在,在维度表设计中碰到的问题(比如维度变化、维度层次、维度一致性、维度整合和拆分等)都会直接关系到维度建模…