当前位置: 首页 > news >正文

JVM面试(七)G1垃圾收集器剖析

概述

上一章我们说了,G1收集器,它属于里程碑式的发展,开创了面向局部收集垃圾的概念。专门针对多核处理器以及大内存的机器。在JDK9中,更是呗指定为官方的GC收集器。满足高吞吐的通知满足GC的STW停顿时间尽可能的短。

虽然现在我们看来这种“化整为零”的解题思路没有多大的创新,也很好理解,但是在运行的时候其实有很多问题。 包括但不限于如下:

  • 多个Region,对于那些跨区引用对象如何解决?
  • 并发标记的时候,怎么保证收集线程和用户线程并行?收集过程中用户改变了对象的引用关系怎么办?
  • 如何预测停顿时间?

下面我们先来完整的了解一下,然后再解答上面的问题。

分区原理

使用G1收集器时,它将整个Java堆划分成约2048个⼤⼩相同的独立Region块,每个Region块大小根据堆空间的实际大小而定,整体被控制在1MB到32MB之间,且为2的N次幂,即1MB, 2MB, 4MB, 8MB, 16MB, 32MB。
可以通过-XX:G1HeapRegionSize设定。所有的Region大小相同,且在JVM⽣命周期内不会被改变。

虽然还保留着新生代和老年代的概念,但新生代和老年代不再是物理隔离的了,它们都是一部分Region (不需要连续)的集合。通过Region的动态分配方式实现逻辑上的连续。
在这里插入图片描述

⼀个region(分区)只能属于⼀个角色,有可能为eden区、S区、老年代等, E表示为Eden区、S区表示为S1,S0区,老年代O区 空白的表示为未使用的分配的内存。H区存放巨型对象

巨型对象

在G1收集器中也有⼀个新的内存区域,称作为:Humongous (H)区(巨型对象),主要存放⼀些比较大的对象,⼀个对象大于region的⼀半时,称之为巨型对象,G1不会对巨型对象进行拷贝,回收时会考虑优先回收。
在以前收集器中,如果是⼀个大对象是直接放入到老年代中,而触发老年代GC不是很频繁,万一该大对象不是非常频繁的使用,则会非常浪费我们堆内存,为了解决这个问题在G1收集器专门弄⼀个H区存放巨型对象。(垃圾回收时,对于H区中的对象会优先回收,来提升内存使用效率)

回收流程

大致可以划分为以下四个步骤:

  • 初始标记(Initial Marking):仅仅只是标记一下GC Roots能直接关联到的对象,并且修改TAMS指针的值,让下一阶段用户线程并发运行时,能正确地在可用的Region中分配新对象。这个阶段需要停顿线程,但耗时很短,而且是借用进行Minor GC的时候同步完成的,所以G1收集器在这个阶段实际并没有额外的停顿。
  • 并发标记(Concurrent Marking):从GC Root开始对堆中对象进行可达性分析,递归扫描整个堆里的对象图,找出要回收的对象,这阶段耗时较长,但可与用户程序并发执行。当对象图扫描完成以后,还要重新处理SATB记录下的在并发时有引用变动的对象。
  • 最终标记(Final Marking):对用户线程做另一个短暂的暂停,用于处理并发阶段结束后仍遗留下来的最后那少量的SATB记录。
  • 筛选回收(Live Data Counting and Evacuation):负责更新Region的统计数据,对各个Region的回收价值和成本进行排序,根据用户所期望的停顿时间来制定回收计划,可以自由选择任意多个Region构成回收集,然后把决定回收的那一部分Region的存活对象复制到空的Region中,再清理掉整个旧Region的全部空间。这里的操作涉及存活对象的移动,是必须暂停用户线程,由多条收集器线程并行完成的。

示意图:
在这里插入图片描述

新生代回收

依然是分代式的回收,新生代回收主要工作就是回收Eden区和Survivor区。一旦Eden区被占满,就会触发年轻代的GC线程,只处理Eden区和部分Survivor区。因为也是要做标记-复制算法,将存活的对象放入另一个Survivor区里面。

老年代

当老年代+大对象 达到堆空间阈值的时候,就会开启并发标记(不会stw)任务。对应的配置参数:
-XX:InitiatingHeapOccupancyPercent=45%

而在并发标记过程中,用户线程变动对象引用产生的漏标问题,G1采用了初始快照算法
snapshot⼀at⼀the⼀beginning (SATB)

记忆集与卡表解决跨区引用

先了解一下什么是记忆集与卡表

记忆集是⼀种用于记录从非收集区域指向收集区域的指针集合的抽象数据结构。卡表就是记忆集的⼀种具体实现,它定义了记忆集的记录精度、与堆内存的映射关系等。

关于卡表与记忆集的关系,可以按照Java语言中HashMap与Map的关系来类比理解。

卡表的数据结构对应⼀个字节数组。CARD_TABLE的每⼀个元素都对应着其标识的内存区域中⼀块特定大小的内存块,这个 内存块被称作“卡页”(Card Page)⼀个卡页的内存中通常
包含不止⼀个对象,只要卡页内有⼀个(或更多)对象的字段存在着跨代指针,那就将对应卡表的数组元素的值标识为1,称为这个元素变脏(Dirty),没有则标识为0。在垃圾收集发生时,只要筛选出卡表中变脏的元素,就能轻易得出哪些卡页内存块中包含跨代指针,把它们加入GC Roots中⼀并扫描。

原始快照 SATB 解决不干扰用户线程

在并发标记过程中,不影响用户线程,首先要解决的是标记过程中用户引用的变动,也就是之前说过的漏标问题,CMS用的是增量更新算法,之前的章节我们说过。而G1用的是原始快照的方法。

原始快照:当对象的引用关系变动的时候,将这个变动的引用关系也记录下来。 在并发标记结束之后,再通过 这些保存下来的对象引用快照,再扫描一次。

预测停顿时间

用户通过-XX:MaxGCPauseMillis参数指定的停顿时间只意味着垃圾收集发生之前的期望值,但G1收集器要怎么做才能满足用户的期望呢?G1收集器的停顿预测模型是以衰减均值(Decaying Average)为理论基础来实现的,在垃圾收集过程中,G1收集器会记录每个Region的回收耗时、每个Region记忆集里的脏卡数量等各个可测量的步骤花费的成本,并分析得出平均值、标准偏差、置信度等统计信息。这里强调的“衰减平均值”是指它会比普通的平均值更容易受到新数据的影响,平均值代表整体平均状态,但衰减平均值更准确地代表“最近的”平均状态。换句话说,Region的统计状态越新越能决定其回收的价值。然后通过这些信息预测现在开始回收的话,由哪些Region组成回收集才可以在不超过期望停顿时间的约束下获得最高的收益。

相关文章:

  • 北京网站建设多少钱?
  • 辽宁网页制作哪家好_网站建设
  • 高端品牌网站建设_汉中网站制作
  • css问题:display:flex布局+justify-content: space-between; 最后一行不能左对齐
  • 2024年重磅报告!国内AI大模型产业飞速发展!
  • APO使用场景之:统一的指标采集展示
  • Android SPN/PLMN 显示逻辑简介
  • 图算法 | 图算法的分类有哪些?(下)
  • HTML 基础知识详解与代码示例
  • Vue3流程图插件-Vue Flow
  • 黑神话 Java,Solon v2.9.2 发布
  • 鸿蒙(API 12 Beta6版)【ArkGraphics 3D资源创建以及使用】方舟3D图形
  • pytest 生成allure测试报告
  • 网络安全 L2 Introduction to Cryptography 密码学
  • 技术接口:日志程序2
  • 今日leetCode 160.链表相交
  • Java 每日一刊(第4期):Java 23 即将发布
  • 基于“硅基”的AI数字人要闻直播
  • 【399天】跃迁之路——程序员高效学习方法论探索系列(实验阶段156-2018.03.11)...
  • ES6简单总结(搭配简单的讲解和小案例)
  • JavaSE小实践1:Java爬取斗图网站的所有表情包
  • 浅谈JavaScript的面向对象和它的封装、继承、多态
  • 世界上最简单的无等待算法(getAndIncrement)
  • 学习使用ExpressJS 4.0中的新Router
  • 移动端唤起键盘时取消position:fixed定位
  • 远离DoS攻击 Windows Server 2016发布DNS政策
  • 3月7日云栖精选夜读 | RSA 2019安全大会:企业资产管理成行业新风向标,云上安全占绝对优势 ...
  • 策略 : 一文教你成为人工智能(AI)领域专家
  • 你学不懂C语言,是因为不懂编写C程序的7个步骤 ...
  • 容器镜像
  • ​VRRP 虚拟路由冗余协议(华为)
  • ​一、什么是射频识别?二、射频识别系统组成及工作原理三、射频识别系统分类四、RFID与物联网​
  • #nginx配置案例
  • $con= MySQL有关填空题_2015年计算机二级考试《MySQL》提高练习题(10)
  • (TOJ2804)Even? Odd?
  • (二刷)代码随想录第16天|104.二叉树的最大深度 559.n叉树的最大深度● 111.二叉树的最小深度● 222.完全二叉树的节点个数
  • (附程序)AD采集中的10种经典软件滤波程序优缺点分析
  • (附源码)计算机毕业设计ssm高校《大学语文》课程作业在线管理系统
  • (更新)A股上市公司华证ESG评级得分稳健性校验ESG得分年均值中位数(2009-2023年.12)
  • (含笔试题)深度解析数据在内存中的存储
  • (教学思路 C#之类三)方法参数类型(ref、out、parmas)
  • (原創) 如何優化ThinkPad X61開機速度? (NB) (ThinkPad) (X61) (OS) (Windows)
  • (转)利用PHP的debug_backtrace函数,实现PHP文件权限管理、动态加载 【反射】...
  • (转载)Linux网络编程入门
  • .apk 成为历史!
  • .net core MVC 通过 Filters 过滤器拦截请求及响应内容
  • .NET Core实战项目之CMS 第一章 入门篇-开篇及总体规划
  • .NET Framework 和 .NET Core 在默认情况下垃圾回收(GC)机制的不同(局部变量部分)
  • .Net FrameWork总结
  • .Net 访问电子邮箱-LumiSoft.Net,好用
  • .one4-V-XXXXXXXX勒索病毒数据怎么处理|数据解密恢复
  • @manytomany 保存后数据被删除_[Windows] 数据恢复软件RStudio v8.14.179675 便携特别版...
  • [000-01-022].第06节:RabbitMQ中的交换机介绍
  • [2017][note]基于空间交叉相位调制的两个连续波在few layer铋Bi中的全光switch——
  • [2021 蓝帽杯] One Pointer PHP
  • [AIGC] Kong:一个强大的 API 网关和服务平台
  • [AutoSAR系列] 1.3 AutoSar 架构
  • [CareerCup][Google Interview] 实现一个具有get_min的Queue