聊聊GC是如何快速枚举根节点的

news2024/11/19 7:31:29

本文已收录至Github,推荐阅读 👉 Java随想录

世界上最快乐的事,莫过于为理想而奋斗。——苏格拉底

文章目录

    • 什么是根节点枚举
    • 根节点枚举存在的问题
    • 如何解决根节点枚举的问题
    • 安全点
    • 安全区域

HotSpot使用的是可达性分析算法,该算法需要进行根节点枚举,查找根节点枚举的过程要做到高效并非一件容易的事情,现在Java应用越做越庞大,光是方法区的大小就常有数百上千兆,里面的类、常量等更是 恒河沙数(一种修辞手法),若要逐个检查以这里为起源的引用肯定得消耗不少时间。

大家可以思考下,如果你是JVM的开发者,你会怎么去做?

看完这一章节,你或许会跟我一样,感叹JVM开发者的智慧。

什么是根节点枚举

顾名思义,根节点枚举就是找出所有的GC Roots

固定可作为GC Roots的节点主要在全局性的引用(例如常量或类静态属性)与执行上下文(例如栈帧中的本地变量表)中。

固定可作为GC Roots的对象包括以下几种(摘抄自《深入理解虚拟机 第3版》):

  • 在虚拟机栈(栈帧中的本地变量表)中引用的对象,譬如各个线程被调用的方法堆栈中使用到的参数、局部变量、临时变量等。
  • 在方法区中常量引用的对象,譬如字符串常量池(String Table)里的引用。
  • 在本地方法栈中JNI(即通常所说的Native方法)引用的对象。
  • Java虚拟机内部的引用,如基本数据类型对应的Class对象,一些常驻的异常对象(比如NullPointExcepiton、OutOfMemoryError)等,还有系统类加载器。
  • 所有被同步锁(synchronized关键字)持有的对象。
  • 反映Java虚拟机内部情况的JMXBean、JVMTI中注册的回调、本地代码缓存等。

根节点枚举存在的问题

迄今为止,所有收集器在根节点枚举这一步骤时都是必须暂停用户线程的,因此毫无疑问根节点枚举与之前提及的整理内存碎片一样会面临相似的“Stop The World”的困扰。根节点枚举必须在一个能保障一致性的快照中才得以进行——这里“一致性”的意思是整个枚举期间执行子系统看起来就像被冻结在某个时间点上。

为什么要这么做?

如果不”冻结”的话,根节点集合的对象引用关系在不断变化,那么分析结果准确性也就无法保证。所以即使是号称停顿时间可控,或者(几乎)不会发生停顿的CMS、G1、ZGC等收集器,在枚举根节点这一步也是必须要停顿的。

如何解决根节点枚举的问题

目前主流Java虚拟机使用的都是准确式垃圾收集(准确式 GC 使用的对象访问定位方式是直接指针访问),所以当用户线程停顿下来之后,其实并不需要一个不漏地检查完所有执行上下文和全局的引用位置,虚拟机应当是有办法直接得到哪些地方存放着对象引用的。
在HotSpot的解决方案里,是使用一组称为OopMap的数据结构来达到这个目的。OopMap可以理解为就是映射表,存储栈上的对象引用的信息,这是一种空间换时间的做法。在 GC Roots 枚举时,只需要遍历每个栈桢的 OopMap,通过 OopMap 存储的信息,快捷地找到 GC Roots。

用大白话说,其实就是用类似映射表这种手段记录下来引用关系,时不时去更新下映射表,然后根节点枚举只需要扫描映射表就知道哪些地方存放引用了,而不用去进行全局扫描。

安全点

OK,问题又来了,既然OopMap是一个映射表,这个表什么时候被更新?要知道引用关系变化是十分频繁的,如果引用每变化一次就更新对应的OopMap,那将会需要大量的额外存储空间,这样垃圾收集伴随而来的空间成本就会变得无法忍受的高昂。

解决这个的办法就是安全点,事实上,只是在“特定的位置”记录了这些信息,这些位置被称为安全点(Safepoint)。因此GC不是随时随地来的,得到达安全点时才可以开始GC

一般会在如下几个位置选择安全点:

  • 循环的末尾
  • 方法临返回前
  • 调用方法之后
  • 抛异常的位置

但是还有一个问题是需要考虑的:如何在垃圾收集发生时让所有线程都跑到最近的安全点,然后停顿下来。

有两种方案可供选择:抢先式中断(Preemptive Suspension)主动式中断(Voluntary Suspension)

  • 抢先式中断:不需要线程的执行代码主动去配合,在垃圾收集发生时,系统首先把所有用户线程全部中断,如果发现有用户线程中断的地方不在安全点上,就恢复这条线程执行,让它一会再重新中断,直到跑到安全点上。现在几乎没有虚机实现采用抢先式中断来暂停线程响应GC事件。
  • 主动式中断:当垃圾收集需要中断线程的时候,不直接对线程操作,仅仅简单地设置一个标志位,各个线程执行过程时会不停地主动去轮询这个标志,一旦发现中断标志为真时就自己在最的安全点上主动中断挂起。轮询标志的地方和安全点是重合的,另外还要加上所有创建对象和其他需要在Java堆上分配内存的地方,这是为了检查是否即将要发生垃圾收集,避免没有足够内存分配新对象。

安全区域

安全点的设计似乎已经完美解决如何停顿用户线程,但是仍然有问题,安全点机制保证了程序执行时,在不太长的时间内就会遇到可进入垃圾收集过程的安全点。但是,程序“不执行”的时候呢?

所谓的程序不执行就是没有分配处理器时间,典型的场景便是用户线程处于Sleep状态或者Blocked状态,这时候线程无法响应虚拟机的中断请求,不能再走到安全的地方去中断挂起自己。对于这种情况,JVM引入安全区域(Safe Region)来解决。

安全区域是指能够确保在某一段代码片段之中,引用关系不会发生变化,因此,在这个区域中任意地方开始垃圾收集都是安全的。我们也可以把安全区域看作被扩展拉伸了的安全点。

当用户线程执行到安全区域里面的代码时,首先会标识自己已经进入了安全区域,那样当这段时间里虚拟机要发起垃圾收集时就不必去管这些已声明自己在安全区域内的线程了。 当线程要离开安全区域时,它要检查虚拟机是否已经完成了根节点枚举(或者垃圾收集过程中其他需要暂停用户线程的阶段),如果完成了,那线程就当作没事发生过,继续执行;否则它就必须一直等待,直到收到可以离开安全区域的信号为止


如果本篇博客有任何错误和建议,欢迎给我留言指正。文章持续更新。

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

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

相关文章

ssm高校大学校园租赁平台的设计与实现java

当今社会,信息技术发展快速。同时,随着生活水平提高,学生有了更大的购买力,这就使得闲置物品增多,校园里物品更新快,使用周期短。而且传统的校园租赁平台,已经不能够满足学生的需求。学院校园租…

人工智能识别图片食物

一、准备食物图片(橘子和苹果)二、识别学习关键代码编写public static void study() throws Exception {//学习Picture picture new Picture();//图片解析类 图片(文件)-三通道矩阵Config config new Config();//现有的环境业务…

一文了解WebSocket及Springboot集成WebSocket

文章目录WebSocket是什么WebSocket通信原理和机制WebSocket协议是什么WebSocket协议和Http协议有什么区别WebSocket常用在那些场景Springboot集成WebSocketpom依赖java相关代码configcomponenthtml代码页面访问效果WebSocket是什么 🍊WebSocket是一种网络通信协议&…

Linux C编程

编写C代码 编辑器:vim,编写.c文件 编译 gcc 源文件 -o 生成可执行文件名 gcc -c:只编译,不链接,生成.o文件 make工具和Makefile文件 make工具:GNU make,是一个文件,用于将源代…

【CANoe示例分析】EthernetCanGW_Test_CN

1、工程路径 此示例工程来自于Vector官网:EthernetCanGW_Test_CN 感兴趣的可以自行下载! 2、示例目的 如何在CANoe中创建一个网关,实现转发以太网报文到多个CAN网络中。该使用案例是对CAN网络进行压力测试 3、示例内容 本示例通过执行Test Module里的测试用例Bus_load…

《电路/电路原理》—戴维宁(南)定理实战演练

前言战前准备什么是戴维南定理?戴维南定理(Thevenins theorem)标准解释:含独立电源的线性电阻单口网络N,就端口特性而言,可以等效为一个电压源和电阻串联的单口网络。电压源的电压等于单口网络在负载开路时…

CSS预处理器、移动端适配

1、预处理器概念 1.1、CSS编写的痛点 CSS作为一种样式语言, 本身用来给HTML元素添加样式是没有问题的。 但是目前前端项目已经越来越复杂, 不再是简简单单的几行CSS就可以搞定的, 我们需要几千行甚至上万行的CSS来完成页面的美化工作。 随着代码量的增加, 必然会造成很多的…

LeetCode-26. 删除有序数组中的重复项

目录题目分析双指针理解代码实现题目来源 26. 删除有序数组中的重复项 题目分析 解法: 双指针 首先注意数组是有序的,那么重复的元素一定会相邻。 要求删除重复元素,实际上就是将不重复的元素移到数组的左侧。 考虑用 2 个指针,…

拉伯证券|7900亿芯片巨头狂跌,发生了什么?

全球芯片巨子忽然爆雷。 英特尔刚刚交出了一份“十分糟糕”的财报。美东时间1月26日美股盘后,英特尔公布的2022第四季度及全年财报显现,第四季度的营收为140亿美元,同比大幅下降32%,不及商场预期;第四季度净亏损7亿美元…

【项目精选】基于SpringBoot和Vue开发的功能强大的图书馆系统(附源码)

功能介绍 图书馆系统功能包括: 1、读者端: 1.智能推荐图书 2.读者在线预约座位 3.读者借阅归还图书 4.图书详情 5.图书评论、评星 6.用户登录、注册、修改个人信息 7.用户自定义图书标签 8.用户报名活动参加活动 9.书架展示和添加删除 10.用户邮件登录…

Win11的两个实用技巧系列之u盘怎么设置密码?

Win11系统u盘怎么设置密码?Win11设置u盘密码的方法win11U盘怎么设置密码?今天小编就为大家带来了Win11设置u盘密码的方法,需要的朋友一起看看吧现在还是有很多用户都在使用U盘来存储一些重要的文件和数据,而为了更好的保护里面的安全&#x…

mongodb的索引操作

Mongodb的索引操作 学习目标 掌握 mongodb索引的创建,删除操作掌握 mongodb查看索引的方法掌握 mongodb创建唯一索引的方法 1. 为什么mongdb需要创建索引 加快查询速度进行数据的去重 2. mongodb创建简单的索引方法 语法:db.集合名.ensureIndex({属…

【手写 Promise 源码】第八篇 - 完善 Promise 并通过 promise-aplus-tests 测试

一,前言 上一篇,实现 Promise 对返回值 x 各种情况的分析和处理,主要涉及以下几个点: 回顾了相关的 Promise A 规范内容;根据 Promise A 规范描述和要求,实现了核心解析方法:resolvePromise&a…

BUUCTF-Reverse Writeup【持续更新】

本文示例程序可见 BUUCTF 官网或者 github easyre | 入门级 方法一:WinHex 打开 easyre.exe,浏览一下字符串,发现有flag方法二:IDA Pro 打开 easyre.exe,能直接看到flag,或者 F5 反汇编看到逻辑是输入两个…

怎么把多个JPG合并成一个PDF?还不快来学

我们通常在处理工作文件时会有很多JPG图片需要传输,不过JPG图片数量一般都非常多,我们需要一张一张的进行传输,不仅会浪费很多时间,还很不方便查看,所以我们就可以及将JPG图片合并到一个PDF文件中,这样就可…

直流电机控制器设计

导读:本文主要介绍了DC-motor电流环和速度环的PI控制器参数的设计,并且简单介绍了设计控制器所需要的背景知识,相关仿真文件的下载地址在文章末尾可供大家下载。 DC-motor 的数学模型 直流电机电枢绕组的电压方程为:

阿里紧急辟谣,全球总部始终在杭州,造谣者请放过民营经济吧

树欲静,而风不止。春节期间又一则关于阿里的谣言,再次广泛传播。谣言称,“阿里在新加坡筹建全球总部”。这则谣言前后,网络上还有许多关于阿里早期创始人移民的各种传言。2023年1月27日下午,阿里集团相关负责人进行了辟…

SparkSQL中4个排序的区别

常用的四个排序BY ORDER BYSORT BYDISTRIBUTE BYCLUSTER BY 此文只是结合官方文档和案例做一下说明下功能 数据集描述 数据如上所示,并手动将分区数设定在2个,默认以 id 字段作为分区依据 原始数据分布 情况如下 相同id的数据都分到了同一个分区内 ORDER BY子句 官网说明: …

JavaScript 执行上下文

什么是执行上下文 JavaScript是一种客户端脚本语言,通常在Web浏览器中执行。当您在浏览器中加载网页时,浏览器会解析HTML文档并创建文档对象模型 (DOM)。在这个过程中,浏览器会寻找包含JavaScript代码的script标签并执行这些代码。 当浏览器…

46.Isaac教程--在机器人应用Deepstream

在机器人应用Deepstream ISAAC教程合集地址: https://blog.csdn.net/kunhe0512/category_12163211.html 文章目录在机器人应用Deepstream技术组件工具技术 NVIDIA DeepStream SDK 为基于 AI 的视频和图像感知以及多传感器处理提供了完整的流分析工具包。 DeepStream 是 NVIDIA…