JVM G1垃圾回收器详细解析

news2025/3/12 12:11:57

G1内存布局

Garbage First(简称G1)收集器摒弃了传统垃圾收集器的严格的内存划分,而是采用了基于Region的内存布局形式和局部回收的设计思路。
在这里插入图片描述
G1垃圾收集器把Java堆划分为2048个大小相等的独立的Region,每个Region大小取值范围为1-32MB,且必须为2的N次幂参数,可以通过-XX:G1HeapRegionSize设定,-XX:G1HeapRegionSize默认为0,此时Region的大小采用Java堆大小/2048的计算公式来确定,取值为最接近的2的N次幂数值。

Region有四种:Eden、survivor、Old、Humongous(用于存储超过1.5个region的大对象),空白表示未使用区域。

G1的特点

分代收集: G1依然属于分代垃圾回收器,它会区分年轻代和老年代,年轻代依然有Eden和Survivor,但是从堆的结构上看,年轻代和老年 代不再物理隔离,而是逻辑上的概念;不要求整个eden、survivor区连续的,也不再坚持固定大小和数量。
避免内存碎片: 有利于程序长时间运行,分配大对象时不会因为无法找到连续的内存空间而提前触发下一次GC。
可预测的停顿时间: G1除了追求低停顿外,还能建立可预测的停顿时间模型,能让使用者明确指定在一个长度为M毫秒的时间片段内,消耗在垃圾回收上的时间不得超过N毫秒,可以通过参数-XX:MaxGCPauseMillis设置。 由于分区的原因, G1跟踪各个Region里面的垃圾堆积的价值大小(回收所获得的空间大小以及回收所需要的时间),在后台维护一个优先列表,每次根据允许的收集时间,优先回收价值最大的Region。保证G1收集器在有限的时间内获取尽可能高的收集效率。

G1的回收阶段划分

年轻代回收(Young GC):仅回收年轻代(Eden和Survivor区)。年轻代通常包含新创建的对象,这些对象更有可能在短时间内变成垃圾。Young GC的执行过程相对较快,因为它只涉及新生代中对象的扫描和回收。
在Young GC过程中,Eden区和Survivor区的存活对象会被复制到另一个Survivor区或者晋升到老年代。这个过程是Stop-The-World(STW)的,意味着在回收过程中,应用程序的所有线程都会被暂停。但是,由于新生代中的可回收对象通常较少,因此这个暂停时间通常较短,对应用程序的性能影响也较小。
并发标记周期(Concurrent Marking Cycle):包含初始标记(Initial Mark)、并发标记(Concurrent Marking)、最终标记(Final Marking)和清理(Cleanup)阶段。并发标记周期完成后,才会触发混合回收(Mixed GC),该阶段会回收部分年轻代和老年代Region。

  • Mixed GC
    当老年代占用率达到参数(-XX:InitiatingHeapOccupancyPercent)设定的值则触发,回收所有的Eden区、Survivor区和部分Old区(根据期望的GC停顿时间和回收收益确定Old区垃圾收集的优先顺序)以及大对象区。
  • Full GC
    在Mixed GC 回收的内存不够的时候触发Full GC,回收全堆。

Young GC的回收策略

Young GC过程中,如果老年代中有对象引用了年轻代中的对象,那么这些年轻代对象在回收过程中不应被错误地清除。Young GC面临一个挑战:如何识别和处理老年代对象对年轻代对象的引用?

厘清概念

记忆集(RememberedSet)

RSet详细记录了如老年代对象引用年轻代对象的关系。在年轻代回收时,RSet中的对象被临时加入到GC Root中,这样垃圾回收器就能够根据引用链准确地判断哪些对象需要回收,哪些对象由于被老年代引用而需要保留。
在这里插入图片描述
为了进一步优化内存使用,G1将每个区域中的内存按照一定大小划分成多个卡页(512B),并为每个卡页分配一个编号。在RSet中,不再记录单个对象的引用关系,而是记录对卡页的引用关系。这样,即使一个卡页中包含多个对象,也只需要记录一次卡页的引用,从而显著减少了内存开销。
在这里插入图片描述
RSet是一种points-into结构(谁引用了我),实际实现是一个Hash Table,Key是别的Region的起始地址,Value是一个集合,里面的元素是卡表(Card Table)的Index。

卡表(Card Table)
G1为所有的Region维护了一张全局的卡表(Card Table),它的核心作用是记录跨代引用(老年代对象引用年轻代对象),是一种points-out(我引用了谁)的结构。卡表的每个卡(Card)通常是一个字节,标记为1表示“脏”,即该卡对应的内存块(512B)有老年代对象引用了年轻代对象。

  • 写屏障(Write Barrier):当发生跨代引用时,写屏障会触发卡表的标记操作,将对应的卡标记为“脏”。
  • RSet的更新:G1的每个Region的RSet通过卡表的脏卡信息,间接记录哪些Region的哪些卡页引用了当前Region的对象。记忆集的粒度更精细,避免全量扫描老年代(避免全量扫描在卡表中被标记为脏卡的卡页中的所有对象)。

Young GC的详细步骤

Young GC过程是Stop-The-World(STW)的。

1.GC Root扫描: 暂停应用线程,标记GC Root直达的对象。
2.处理脏卡:检查卡表中的脏卡,更新记忆集。
3.标记存活对象: 基于GC Root和记忆集的信息,G1会递归遍历所有被引用的对象,标记为存活,未被标记的对象即为垃圾。
4.选择回收集合: 根据停顿时间目标(-XX:MaxGCPauseMillis),动态计算哪些Region回收性价比最高,优先回收。

Mixed GC的详细步骤

上文提到,并发标记周期(Concurrent Marking Cycle)完成后,才会触发Mixed GC,并发标记周期如下所示。
在这里插入图片描述
1.初始标记(Initial Mark,STW)

这一阶段标记了从GC Root开始直接可达的对象。
G1垃圾回收器采用了三色标记法来识别对象的状态。

  • 黑色:当前对象不仅在GC Root的引用链上,而且它所引用的所有对象也已经被标记为存活。在位图中,相应的bit位被标识为1。
  • 灰色:当前对象在GC Root的引用链上,但其引用的其他对象尚未被标记。灰色对象不会直接体现在位图中,而是被放入一个专门的队列中,等待后续处理。
  • 白色:当前对象不在GC Root的引用链上,可被回收。在位图中,相应的bit位被标识为0。
    在这里插入图片描述

2.并发标记(Concurrent Marking)
这一阶段处理在初始标记阶段中放入灰色队列中的对象。
示例如上图和下图所示:从灰色队列中提取出对象B,并对其关联的A和C对象进行标记,A对象并未引用其他任何对象,因此可以立即标记为黑色,C对象引用了另一个对象E,因此C对象被标记为灰色,被放入灰色队列中等待进一步处理。同时,B对象已完成了对其所有引用对象的标记,因此也将B对象标记为黑色…下一轮标记和上面是一样的逻辑,直至灰色队列为空。

在这里插入图片描述
然而,三色标记法存在一个潜在的问题,即用户线程可能同时修改对象的引用关系,导致标记结果出现错误,如下图所示。
在这里插入图片描述
G1为了解决这个问题,使用了SATB算法(Snapshot At The Beginning, 初始快照)。
SATB算法的核心思想是在并发标记过程的起始阶段捕捉对象图的“逻辑快照”,并基于这个快照来进行后续的标记工作。在这个快照之后新生成的对象,会被直接标记为黑色,表示它们是活跃的,不应该被回收(可能会产生浮动垃圾)。
为了处理在标记过程中可能发生的对象引用变化,SATB算法采用了前置写屏障技术。这种技术会在引用赋值操作(B.c = new C()B.c = null)前触发,目的是捕获可能被删除的旧引用放入SATB待处理队列中。每个线程都有自己的SATB队列,但最终这些队列会被汇总到一个全局SATB队列中。

3.最终标记(Remark,STW)

后台的并发标记线程从全局SATB队列中取出对象,将其重新标记为灰色,并重新扫描其引用,将其子对象被递归标记为黑色。

4.清除垃圾(Cleanup)

依赖并发标记周期产生的数据,进行Mixed GC,回收所有Young区和部分Old区(对Old区的回收价值和成本进行排序,根据用户所期望的停顿时间来制定回收计划。

参考资料

https://segmentfault.com/a/1190000044966735
https://www.cnblogs.com/meixiaoyu/articles/16672125.html
https://www.bilibili.com/opus/662248429116719137
https://developer.aliyun.com/article/1502777

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

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

相关文章

OpenGL中绘制图形元素的实现(使用visual studio(C++)绘制一个矩形)

目标&#xff1a;使用OpenGL提供的函数绘制矩形、线段、三角形等基本图形元素 所需效果 实验步骤 1、配置OpenGL&#xff08;详情参见OpenGL的配置&#xff09; 2、头文件引入 #include <gl/glut.h> 3、编写方法体 1>矩形实现 //绘制矩形 void DisplayRectangl…

数据库---sqlite3

数据库&#xff1a; 数据库文件与普通文件区别: 1.普通文件对数据管理(增删改查)效率低 2.数据库对数据管理效率高,使用方便 常用数据库: 1.关系型数据库: 将复杂的数据结构简化为二维表格形式 大型:Oracle、DB2 中型:MySql、SQLServer …

【阿里云】控制台使用指南:从创建ECS到系统诊断测评

前言 随着云计算技术的快速发展&#xff0c;越来越多的企业和开发者开始使用云服务来部署和管理应用程序。在众多云服务提供商中&#xff0c;阿里云&#xff08;Alibaba Cloud&#xff09;凭借其强大的基础设施和丰富的服务&#xff0c;成为了众多用户的首选。本文旨在介绍如何…

简易的微信聊天网页版【项目测试报告】

文章目录 一、项目背景二、项目简介登录功能好友列表页面好友会话页面 三、测试工具和环境四、测试计划测试用例部分人工手动测试截图web自动化测试测试用例代码框架配置内容代码文件&#xff08;Utils.py&#xff09;登录页面代码文件&#xff08;WeChatLogin.py&#xff09;好…

基于腾讯云高性能HAI-CPU的跨境电商客服助手全链路解析

跨境电商的背景以及痛点 根据Statista数据&#xff0c;2025年全球跨境电商市场规模预计达6.57万亿美元&#xff0c;年增长率保持在12.5% 。随着平台规则趋严&#xff08;如亚马逊封店潮&#xff09;&#xff0c;更多卖家选择自建独立站&#xff0c;2024年独立站占比已达35%。A…

北京迅为RK3568开发板OpenHarmony系统南向驱动开发内核HDF驱动框架架构

瑞芯微RK3568芯片是一款定位中高端的通用型SOC&#xff0c;采用22nm制程工艺&#xff0c;搭载一颗四核Cortex-A55处理器和Mali G52 2EE 图形处理器。RK3568 支持4K 解码和 1080P 编码&#xff0c;支持SATA/PCIE/USB3.0 外围接口。RK3568内置独立NPU&#xff0c;可用于轻量级人工…

从0到1入门Docker

一、快速入门 Docker run命令中的常见参数 -d&#xff1a;让容器后台运行--name&#xff1a;给容器命名&#xff08;唯一&#xff09;-e&#xff1a;环境变量-p&#xff1a;宿主机端口映射到容器内端口镜像名称结构&#xff1a;Repository &#xff1a;TAG&#xff08;镜像名&…

应用篇| 抓包工具-charles的使用

上文说到,我们app爬虫要借助一些抓包工具,本节课就教大家如何使用抓包工具分析app的流量。抓包工具的使用是app爬虫的必修课。相比 Fiddler 来说,Charles 的功能更强大,而且跨平台支持更好。 charles安装 官方网站:https://www.charlesproxy.com 下载链接:Download a F…

Docker搭建Redis哨兵模式【一主两从三哨兵】

Docker搭建Redis哨兵模式 系统: CentOS 7 Dockder 版本: VMware虚拟机 网络适配器 网络连接 桥接模式:直接连接物理网络查看IP命令 ip addr一、哨兵模式概述 1. 官方文档与关联博客 官方文档:https://redis.io/docs/latest/operate/oss_and_stack/management/sentinel关联博…

labview实现大小端交换移位

在解码时遇到了大小端交换的问题&#xff0c;需要把高低字节的16进制值进行互换&#xff0c;这里一时间不知道怎么操作&#xff0c;本来打算先把16进制转字节数组&#xff0c;算出字节数组的大小&#xff0c;然后通过模2得到0&#xff0c;1&#xff0c;来判断是否为奇数位和偶数…

Three.js 进阶(灯光阴影关系和设置、平行光、阴影相机)

本篇主要学习内容 : 灯光与阴影聚光灯点光源平行光阴影相机和阴影计算投射阴影接受阴影 点赞 关注 收藏 学会了 1.灯光与阴影 1、材质要满足能够对光有反应 2、设置渲染器开启阴影计算 renderer.shadowMap.enabledtrue 3、设置光照投射阴影 directionalLight.castShadow …

RK3588部署YOLOv8(2):OpenCV和RGA实现模型前处理对比

目录 前言 1. 结果对比 1.1 时间对比 1.2 CPU和NPU占用对比 2. RGA实现YOLO前处理 2.1 实现思路 2.2 处理类的声明 2.3 处理类的实现 总结 前言 RK平台上有RGA (Raster Graphic Acceleration Unit) 加速&#xff0c;使用RGA可以减少资源占用、加速图片处理速度。因此…

打造智能钉钉机器人:借助智谱GLM-4-Flash实现高效智能回复(文末附源码)

文章目录 前言一、准备工作&#xff08;一&#xff09;钉钉机器人&#xff08;二&#xff09;智谱 GLM-4-Flash&#xff08;三&#xff09;内网穿透工具 cpolar&#xff08;四&#xff09;需要准备的工具和环境 二、钉钉机器人的创建与配置步骤1&#xff1a;创建钉钉机器人步骤…

使用Mermaid语法绘制的C语言程序从Linux移植到Windows的流程图

以下是使用Mermaid语法绘制的C语言程序从Linux移植到Windows的流程图&#xff1a; graph TDA[开始移植] --> B[代码兼容性检查]B --> C[检查系统调用差异\nfork/exec -> CreateProcess]B --> D[检查文件路径格式\n/ vs \\]B --> E[检查依赖库兼容性\nPOSIX vs …

入门到入土,Java学习 day16(算法1)

利用循环遍历来判断是否相等 二分查找/折半查找 前提条件&#xff1a;数组中的数据有序 每次排除一般的查找范围 用min,max,mid来处理&#xff0c;最大加最小除2&#xff0c;比较&#xff0c;然后得到在中间左边还是右边然后更新最大最小 public class Two {// 二分查找方法…

Vulnhub 靶机 VulnOSv2 write up opendocman cms 32075 sql注入 账号密码 ssh连接 37292.c 脏牛提权

Vulnhub 靶机 VulnOSv2 write up opendocman cms 32075 sql注入 账号密码 ssh连接 37292.c 脏牛提权 一、信息收集 1、首先拿到靶场先扫一下ip arp-scan -l 3、 2、指纹扫描 nmap -sS -sV 192.168.66.178nmap -p- -sV -A 192.168.66.253 PORT STATE SERVICE VERSION 22…

Unity辅助工具_头部与svn

Unity调用者按钮增加PlaySideButton using QQu; using UnityEditor; using UnityEngine; [InitializeOnLoad] public class PlaySideButton {static PlaySideButton(){UnityEditorToolbar.RightToolbarGUI.Add(OnRightToolbarGUI);UnityEditorToolbar.LeftToolbarGUI.Add(OnLe…

DeepLabv3+改进8:在主干网络中添加SIM注意力机制|助力涨点

🔥【DeepLabv3+改进专栏!探索语义分割新高度】 🌟 你是否在为图像分割的精度与效率发愁? 📢 本专栏重磅推出: ✅ 独家改进策略:融合注意力机制、轻量化设计与多尺度优化 ✅ 即插即用模块:ASPP+升级、解码器 PS:订阅专栏提供完整代码 论文简介 在本文中,我们提出了…

电路原理(电容 集成电路NE555)

电容 1.特性&#xff1a;充放电&#xff0c;隔直流&#xff0c;通交流 2.电容是通过聚集正负电荷来存储电能的 3.电容充放电过程可等效为导通回路 4.多电容并联可以把容量叠加&#xff0c;但是多电容串联就不会&#xff0c;只会叠加电容的耐压值。 6.电容充放电时相当于通路&a…

函数式编程的核心

函数式编程 函数式编程&#xff08;funcitonal programming&#xff09;其实是个很古老的概念。 高阶函数和内存分析 函数式一阶公民 函数式编程最鲜明的特点就是&#xff1a;函数式一等公民&#xff0c;指的是函数与其他数据类型一样&#xff0c;处于平等地位&#xff0c;可…