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

jvm_根节点枚举安全点安全区域

1、可达性分析可以分成两个阶段

根节点枚举
从根节点开始遍历对象图
前文我们在介绍垃圾收集算法的时候,简单提到过:标记-整理算法(Mark-Compact)中的移动存活对象操作是一种极为负重的操作,必须全程暂停用户应用程序才能进行,像这样的停顿被最初的虚拟机设计者形象地描述为 “Stop The World (STW)”。

显然 STW 并不是一件好事,能够避免那就需要尽可能避免。

在可达性分析中,第一阶段 ”可达性分析“ 是必须 STW 的,而第二阶段 ”从根节点开始遍历对象图“,如果不进行 STW 的话,会导致一些问题,由于第二阶段时间比较长,长时间的 STW 很影响性能,所以大佬们设计了一些解决方案,从而使得这个第二阶段可以不用 STW(详见三色标记法),大幅减少时间。

先这样笼统的介绍下,大伙儿对可达性分析的整体脉络有个认识就行,下面会详细解释,我会分两篇文章来写,本篇就先来分析第一阶段 ”可达性分析“!

1.1、根节点枚举

迄今为止,所有收集器在根节点枚举这一步骤时都是必须暂停用户线程的,枚举过程必须在一个能保障 ”一致性“ 的快照中才得以进行。

通俗来说,整个枚举期间整个系统看起来就像被冻结在某个时间点上,不会出现在分析过程中,用户进程还在运行,导致根节点集合的对象引用关系还在不断变化的情况,若这点都不能满足的话,可达性分析结果的准确性显然也就无法保证。

也就是说,根节点枚举与我们之前提到的标记-整理算法(Mark-Compact)中的移动存活对象操作一样会面临相似的 “Stop The World” 的困扰。

另外,众所周知,可作为 GC Roots 的对象引用就那么几个,主要在全局性的引用(例如常量或类静态属性)与执行上下文(例如虚拟机栈中引用的对象)中,尽管目标很明确,但查找过程要做到快速高效其实并不是一件容易的事情。

现在 Java 应用越做越庞大,光是方法区的大小就常有数百上千兆,里面的类、常量等更是一大堆,要是把这些区域全都扫描检查一遍显然太过于费事。

那有没有办法减少耗时呢?

一个很自然的想法,空间换时间!
把引用类型和它对应的位置信息用哈希表记录下来,这样到 GC 的时候就可以直接读取这个哈希表,而不用一个区域一个区域地进行扫描了。Hotspot 就是这么实现的,这个用于存储引用类型的数据结构叫 OopMap。

下图是 HotSpot 虚拟机客户端模式下生成的一段 String::hashCode() 方法的本地代码,可以看到在 0x026eb7a9 处的 call 指令有 OopMap 记录,它指明了 EBX 寄存器和栈中偏移量为 16 的内存区域中各有一个 OopMap 的引用,有效范围为从 call 指令开始直到0x026eb730(指令流的起始位置)+ 142(OopMap 记录的偏移量)= 0x026eb7be,即 hlt 指令为止。

实话实说,这段不理解也就算了,知道 OopMap 是这么一个东西就行了。

在这里插入图片描述

2、 安全点 Safe Point

在 OopMap 的协助下,HotSpot 可以快速完成根节点枚举了,但一个很现实的问题随之而来:由于引用关系可能会发生变化,这就会导致 OopMap 内容变化的指令非常多,如果为每一条指令都生成对应的 OopMap,那将会需要大量的额外存储空间,这样垃圾收集伴随而来的空间成本就会变得无法忍受的高昂。

所以实际上 HotSpot 也确实没有为每条指令都生成 OopMap,只是在 “特定的位置” 生成 OopMap,换句话说,只有在某些 ”特定的位置“ 上才会把对象引用的相关信息给记录下来,这些位置也被称为安全点(Safepoint)。

有了安全点的设定,也就决定了用户程序执行时并不是随便哪个时候都能够停顿下来开始 GC 的,而是强制要求程序必须执行到达安全点后才能够进行 GC(因为不到达安全点话,没有 OopMap,虚拟机就没法快速知道对象引用的位置呀,没法进行根节点枚举)。

如下图所示:
在这里插入图片描述

因此,安全点的设定既不能太少以至于让垃圾收集器等待时间过长,也不能太多以至于频繁进行垃圾收集从而导致运行时的内存负荷大幅增大。所以,安全点的选定基本上是以 “是否具有让程序长时间执行的特征” 为标准进行选定的,最典型的就是指令序列的复用:例如方法调用、循环跳转、异常跳转等,所以只有具有这些功能的指令才会产生安全点。

对于安全点,另外一个需要考虑的问题是,如何在 GC 发生时让所有用户线程都执行到最近的安全点,然后停顿下来呢?。这里有两种方案可供选择:

抢先式中断(Preemptive Suspension):这种思路很简单,就是在 GC 发生时,系统先把所有用户线程全部中断掉。然后如果发现有用户线程中断的位置不在安全点上,就恢复这条线程执行,直到跑到安全点上再重新中断。
抢先式中断的最大问题是时间成本的不可控,进而导致性能不稳定和吞吐量的波动,特别是在高并发场景下这是非常致命的,所以现在几乎没有虚拟机实现采用抢先式中断来暂停线程响应 GC 事件。

主动式中断(Voluntary Suspension):主动式中断不会直接中断线程,而是全局设置一个标志位,用户线程会不断的轮询这个标志位,当发现标志位为真时,线程会在最近的一个安全点主动中断挂起。现在的虚拟机基本都是用这种方式。

3、 安全区域 Safe Region

安全点机制保证了程序执行时,在不太长的时间内就会遇到可进入垃圾收集过程的安全点。

对于主动式中断来说,用户线程需要不断地去轮询标志位,那对于那些处于 sleep 或者 blocked 状态的线程(不在活跃状态的线程)来说怎么办?

这些不在活跃状态的线程没有获得 CPU 时间,没法去轮询标志位,自然也就没法找到最近的安全点主动中断挂起了。

换句话说,对于这些不活跃的线程,我们没法掌控它们醒过来的时间。很可能其他线程都已经通过轮询标志位到达安全点被中断了,然后虚拟机开始根节点枚举了(根节点枚举需要暂停所有用户线程),但是这时候那些本不活跃的用户线程又醒过来了开始执行,破坏了对象之间的引用关系,那显然是不行的。

对于这种情况,就必须引入安全区域(Safe Region)来解决。

安全区域的定义是这样的:确保在某一段代码片段之中,引用关系不会发生变化,因此,在这个区域中的任意地方开始 GC 都是安全的。

可以简单地把安全区域看作被拉长了的安全点。

当用户线程执行到安全区域里面的代码时,首先会标识自己已经进入了安全区域。那样当这段时间里虚拟机要发起 GC 时,就不必去管这些在安全区域内的线程了。当安全区域中的线程被唤醒并离开安全区域时,它需要检查下主动式中断策略的标志位是否为真(虚拟机是否处于 STW 状态),如果为真则继续挂起等待(防止根节点枚举过程中这些被唤醒线程的执行破坏了对象之间的引用关系),如果为假则标识还没开始 STW 或者 STW 刚刚结束,那么线程就可以被唤醒然后继续执行。

相关文章:

jvm_根节点枚举安全点安全区域

1、可达性分析可以分成两个阶段 根节点枚举 从根节点开始遍历对象图 前文我们在介绍垃圾收集算法的时候,简单提到过:标记-整理算法(Mark-Compact)中的移动存活对象操作是一种极为负重的操作,必须全程暂停用户应用程序才能进行,像这…...

fabric(token-erc-20链码部署)

确保自己已经安装了fabric。没有安装的可以参考我之前的教程fabric中bootstrap.sh到底帮助我们干了什么?(手动执行相关操作安装fabric2.4)_./bootstrap.sh_小小小小关同学的博客-CSDN博客小伙伴们在跟着官方示例来安装fabric的时候都是相当烦…...

C语言基础——流程控制语句

文章目录一、流程控制语句 -- 控制程序的运行过程 9条(一)、条件选择流程控制语句:if语句if……else……语句if……else if……语句switch语句(二)、循环流程控制语句:for语句while语句do while……语句co…...

WinForm | C# 界面弹出消息通知栏 (仿Win10系统通知栏)

ApeForms 弹出消息通知栏功能 文章目录ApeForms 弹出消息通知栏功能前言全局API通知栏起始方向通知排列方向通知栏之间的间隔距离无鼠标悬停时的不透明度消息通知窗体的默认大小示例代码文本消息提示栏文本消息提示栏(带选项)图文消息提示栏图文消息提示…...

刷题之最长公共/上升子序列问题

目录 一、最长公共子序列问题(LCS) 1、题目 2、题目解读 ​编辑 3、代码 四、多写一题 五、应用 二、最长上升子序列问题(LIS) 1、题目 2、题目解读 3、代码 四、多写一道 Ⅰ、题目解读 Ⅱ、代码 一、最长公共子序列问题&…...

【数据结构】千字深入浅出讲解栈(附原码 | 超详解)

🚀write in front🚀 📝个人主页:认真写博客的夏目浅石. 🎁欢迎各位→点赞👍 收藏⭐️ 留言📝 📣系列专栏:C语言实现数据结构 💬总结:希望你看完…...

自动驾驶V2X

1 SoC MDM9250 2 设备网络节点 mhi_swip0 rmnet_mhi0 3 网络协议栈log打印控制 include/linux/netdevice.h ethtool -s eth0 msglvl [level] ethtool -s eth0 msglvl 0x6001 4 URLs MHI initial design review https://lore.kernel.org/lkml/001601d52148$bd852840$388f78c0$c…...

零基础自学网络安全/渗透测试有哪些常见误区?

一、网络安全学习的误区 1.不要试图以编程为基础去学习网络安全 不要以编程为基础再开始学习网络安全,一般来说,学习编程不但学习周期长,且过渡到网络安全用到编程的用到的编程的关键点不多。一般人如果想要把编程学好再开始学习网络安全往…...

ConvMixer:Patches Are All You Need

Patches Are All You Need 发表时间:[Submitted on 24 Jan 2022]; 发表期刊/会议:Computer Vision and Pattern Recognition; 论文地址:https://arxiv.org/abs/2201.09792; 代码地址:https:…...

day10—编程题

文章目录1.第一题1.1题目1.2思路1.3解题2.第二题2.1题目2.2涉及的相关知识2.3思路2.4解题1.第一题 1.1题目 描述: 给定一个二维数组board,代表棋盘,其中元素为1的代表是当前玩家的棋子,0表示没有棋子,-1代表是对方玩…...

如何测量锂电池的电量

锂电池在放电时我们有时需要知道电池的实时电量,如电池电量低了我们就需要及时给锂电池充电,避免电池过度放电。我手里的这个就是个单节锂电池电量显示模块,只需要将这个模块接到锂电池的正负极即可显示电量。这个模块的电量分为四档&#xf…...

菜鸟刷题Day6

⭐作者:别动我的饭 ⭐专栏:菜鸟刷题 ⭐标语:悟已往之不谏,知来者之可追 一.链表内指定区间反转:链表内指定区间反转_牛客题霸_牛客网 (nowcoder.com) 描述 将一个节点数为 size 链表 m 位置到 n 位置之间的区间反转…...

DecimalFormat格式化显示数字

DecimalFormat 是 NumberFormat 的一个具体子类,用于格式化十进制数字,可以实现以最快的速度将数字格式化为你需要的样子。 DecimalFormat 类主要靠 # 和 0 两种占位符号来指定数字长度。0 表示如果位数不足则以 0 填充, # 表示只要有可能就…...

cpu中缓存简介

一级缓存是什么: 一级缓存都内置在CPU内部并与CPU同速运行,可以有效的提高CPU的运行效率。一级缓存越大,CPU的运行效率越高,但受到CPU内部结构的限制,一级缓存的容量都很小。 CPU缓存(Cache Memory&#xf…...

【数据结构】二叉树的遍历以及基本操作

目录 1.树形结构 1.概念 2.二叉树 2.1概念 2.2 两种特殊的二叉树 2.3二叉树的存储 2.4二叉树的基本操作 1.手动快速创建一棵简单的二叉树 2.二叉树的遍历 (递归) 3.二叉树的层序遍历 4.获取树中节点的个数 5.获取叶子节点的个数 6.获取第K层节点的个数 7.获取二叉…...

若依框架 --- ruoyi 表格的设置

表格 字典值转换 (1) 方式1:使用字典枚举的方式 var isDownload [[${dict.getType(YES_OR_NO)}]];{field : isDownload,title : 是否允许下载,formatter: function(value, row, index) {return $.table.selectDictLabel(isDownload, value);} }, (2) 方式2&…...

“两会”网络安全相关建议提案回顾

作为新一年的政治、经济、社会等发展的“风向标”,今年“两会”在3月13日顺利闭幕。在今年“两会”期间,多位人大代表也纷纷围绕网络安全、数据安全的未来发展做了提案和建议。 01 “两会”网络安全相关建议和提案回顾 建议统筹智能网联汽车数据收集与共…...

一篇文章带你真正了解接口测试(附视频教程+面试真题)

目录 一、什么是接口测试? 二、为什么要做接口测试? 三、如何开展接口测试? 四、接口测试常见面试题 一、什么是接口测试? 所谓接口,是指同一个系统中模块与模块间的数据传递接口、前后端交互、跨系统跨平台跨数据…...

C/C++每日一练(20230325)

目录 1. 搜索插入位置 🌟 2. 结合两个字符串 🌟 3. 同构字符串 🌟 🌟 每日一练刷题专栏 🌟 Golang每日一练 专栏 Python每日一练 专栏 C/C每日一练 专栏 Java每日一练 专栏 1. 搜索插入位置 给定一个排序数…...

Linux操作系统ARM指令集与汇编语言程序设计

一、实验目的1.了解并掌握ARM汇编指令集2.应用ARM指令集编写一个程序操控开发板上的LED灯二、实验要求应用ARM汇编指令集编写程序,实现正常状态下开发板上的LED灯不亮,按下一个按键之后开发板上的LED灯进入流水灯模式。三、实验原理四个LED灯的电路如下图…...

IDEA运行Tomcat出现乱码问题解决汇总

最近正值期末周,有很多同学在写期末Java web作业时,运行tomcat出现乱码问题,经过多次解决与研究,我做了如下整理: 原因: IDEA本身编码与tomcat的编码与Windows编码不同导致,Windows 系统控制台…...

《Qt C++ 与 OpenCV:解锁视频播放程序设计的奥秘》

引言:探索视频播放程序设计之旅 在当今数字化时代,多媒体应用已渗透到我们生活的方方面面,从日常的视频娱乐到专业的视频监控、视频会议系统,视频播放程序作为多媒体应用的核心组成部分,扮演着至关重要的角色。无论是在个人电脑、移动设备还是智能电视等平台上,用户都期望…...

React第五十七节 Router中RouterProvider使用详解及注意事项

前言 在 React Router v6.4 中&#xff0c;RouterProvider 是一个核心组件&#xff0c;用于提供基于数据路由&#xff08;data routers&#xff09;的新型路由方案。 它替代了传统的 <BrowserRouter>&#xff0c;支持更强大的数据加载和操作功能&#xff08;如 loader 和…...

逻辑回归:给不确定性划界的分类大师

想象你是一名医生。面对患者的检查报告&#xff08;肿瘤大小、血液指标&#xff09;&#xff0c;你需要做出一个**决定性判断**&#xff1a;恶性还是良性&#xff1f;这种“非黑即白”的抉择&#xff0c;正是**逻辑回归&#xff08;Logistic Regression&#xff09;** 的战场&a…...

从深圳崛起的“机器之眼”:赴港乐动机器人的万亿赛道赶考路

进入2025年以来&#xff0c;尽管围绕人形机器人、具身智能等机器人赛道的质疑声不断&#xff0c;但全球市场热度依然高涨&#xff0c;入局者持续增加。 以国内市场为例&#xff0c;天眼查专业版数据显示&#xff0c;截至5月底&#xff0c;我国现存在业、存续状态的机器人相关企…...

【解密LSTM、GRU如何解决传统RNN梯度消失问题】

解密LSTM与GRU&#xff1a;如何让RNN变得更聪明&#xff1f; 在深度学习的世界里&#xff0c;循环神经网络&#xff08;RNN&#xff09;以其卓越的序列数据处理能力广泛应用于自然语言处理、时间序列预测等领域。然而&#xff0c;传统RNN存在的一个严重问题——梯度消失&#…...

使用van-uploader 的UI组件,结合vue2如何实现图片上传组件的封装

以下是基于 vant-ui&#xff08;适配 Vue2 版本 &#xff09;实现截图中照片上传预览、删除功能&#xff0c;并封装成可复用组件的完整代码&#xff0c;包含样式和逻辑实现&#xff0c;可直接在 Vue2 项目中使用&#xff1a; 1. 封装的图片上传组件 ImageUploader.vue <te…...

ServerTrust 并非唯一

NSURLAuthenticationMethodServerTrust 只是 authenticationMethod 的冰山一角 要理解 NSURLAuthenticationMethodServerTrust, 首先要明白它只是 authenticationMethod 的选项之一, 并非唯一 1 先厘清概念 点说明authenticationMethodURLAuthenticationChallenge.protectionS…...

Ascend NPU上适配Step-Audio模型

1 概述 1.1 简述 Step-Audio 是业界首个集语音理解与生成控制一体化的产品级开源实时语音对话系统&#xff0c;支持多语言对话&#xff08;如 中文&#xff0c;英文&#xff0c;日语&#xff09;&#xff0c;语音情感&#xff08;如 开心&#xff0c;悲伤&#xff09;&#x…...

Java线上CPU飙高问题排查全指南

一、引言 在Java应用的线上运行环境中&#xff0c;CPU飙高是一个常见且棘手的性能问题。当系统出现CPU飙高时&#xff0c;通常会导致应用响应缓慢&#xff0c;甚至服务不可用&#xff0c;严重影响用户体验和业务运行。因此&#xff0c;掌握一套科学有效的CPU飙高问题排查方法&…...