浅谈 JVM GC 的安全点与安全区域
OopMap
前文我们说到,JVM 采用的可达性分析法有个缺点,就是从 GC Roots
找引用链耗时。
都说他耗时,他究竟耗时在哪里?
GC 进行扫描时,需要查看每个位置存储的是不是引用类型,如果是,其所引用的对象就不能被回收;如果不是,那就是基本类型,这些肯定是不会引用对象的;这种对 GC 无用的基本类型的数据非常多,每次 GC 都要去扫描,显然是非常浪费时间的。
而且迄今为止,所有收集器在 GC Roots
枚举这一步骤都是必须暂停用户线程的。
那有没有办法减少耗时呢?
一个很自然的想法,能不能用空间换时间? 把栈上的引用类型的位置全部记录下来,这样到 GC 的时候就可以直接读取,而不用一个个扫描了。Hotspot 就是这么实现的,这个用于存储引用类型的数据结构叫 OopMap
。
OopMap
这个词可以拆成两部分:Oop
和 Map
,Oop
的全称是 Ordinary Object Pointer
普通对象指针,Map
大家都知道是映射表,组合起来就是 普通对象指针映射表。
在 OopMap
的协助下,HotSpot 就能快速准确地完成 GC Roots
枚举啦。
安全点
OopMap
的更新,从直观上来说,需要在对象引用关系发生变化的时候修改。不过导致引用关系变化的指令非常多,如果对每条指令都记录 OopMap
的话 ,那将会需要大量的额外存储空间,空间成本就会变得无法忍受的高昂。选用一些特定的点来记录就能有效的缩小需要记录的数据量,这些特定的点就称为 安全点 (Safepoint)。
有了安全点,当 GC 回收需要停止用户线程的时候,将设置某个中断标志位,各个线程不断轮询这个标志位,发现需要挂起时,自己跑到最近的安全点,更新完 OopMap
才能挂起。这主动式中断的方式是绝大部分现代虚拟机选择的方案,另一种抢占式就不介绍了。
安全点不是任意的选择,既不能太少以至于让收集器等待时间过长,也不能过多以至于过分增大运行时的内存负荷。通常选择一些执行时间较长的指令作为安全点,如方法调用、循环跳转和异常跳转等。
安全区域
使用安全点的设计似乎已经完美解决如何停顿用户线程,让虚拟机进入垃圾回收状态的问题了。但是,如果此时线程正处于 Sleep
或者 Blocked
状态,该怎么办?这些线程他不会自己走到安全点,就停不下来了。这个时候,安全点解决不了问题,需要引入 安全区域 (Safe Region)。
安全区域指的是,在某段代码中,引用关系不会发生变化,线程执行到这个区域是可以安全停下进行 GC 的。因此,我们也可以把 安全区域 看做是扩展的安全点。
当用户线程执行到安全区域里面的代码时,首先会标识自己已经进入了安全区域。那样当这段时间里虚拟机要发起 GC 时,就不必去管这些在安全区域内的线程了。当线程要离开安全区域时,它要检查虚拟机是否处于 STW 状态,如果是,则需要等待直到恢复。
总结
HotSpot 使用 OopMap
把引用类型的指针记录下来,让 GC Roots
的枚举变得快速准确。
为了减少更新 OopMap
的开销,引入了 安全点。GC STW 时,线程需要跑到距离自己最近的安全点,更新完 OopMap
才能挂起。
处于Sleep
或者 Blocked
状态的线程无法跑到安全点,需要引入安全区域。GC 的时候,不会去管处于安全区域的线程,线程离开安全区域的时候,如果处于 STW 则需要等待直至恢复。
浅谈 JVM GC 的安全点与安全区域的更多相关文章
- 浅谈jvm中的垃圾回收策略
下面小编就为大家带来一篇浅谈jvm中的垃圾回收策略.小编觉得挺不错的,现在就分享给大家,也给大家做个参考.一起跟随小编过来看看吧 java和C#中的内存的分配和释放都是由虚拟机自动管理的,此前我已 ...
- 浅谈JVM内存模型
JAVA虚拟机在执行JAVA程序的时候,会把它管理的内存分成若干不同的数据区域,每个区域都有各自的用途.目前大致把JVM内存模型划分为五个区域:程序计数器,虚拟机栈,本地方法栈,堆和方法区. 程序计数 ...
- 浅谈 JVM 结构体系、类加载、JDK JRE JVM 三者的关系
一.java类,创建.编译.到运行的工程: 1.随便建一个Java类,保存后就是一个.java文件, 2.然后我们使用 javac命令编译 .java文件,生产 .class文件. 3.再然后使用 j ...
- 浅谈JVM线程调度机制及主要策略
在之前有说过线程,应该都知道,所谓线程就是进程中的一个子任务,一个进程有多个线程.今天的话主要就是谈一谈JVM线程调度机制.我们结合线程来说,当我们在做多线程的案例时,如一个经典案例,火车站卖票. * ...
- 浅谈JVM垃圾回收
JVM内存区域 要想搞懂啊垃圾回收机制,首先就要知道垃圾回收主要回收的是哪些数据,这些数据主要在哪一块区域. Java8和Java8之前的相同点有很多. 都有虚拟机栈,本地方法栈,程序计数器,这三个是 ...
- 浅谈JVM内存区域划分
好吧,虽说真的有看过<深入分析Java Web技术内幕>一书,但当时看的时候还是一知半解,稀里糊涂的看完了.本来是打算暑假拿起来再看一遍的,但是早两天一个阿里学长给我做了个小面试,让我颇受 ...
- 浅谈jvm
1 .说起jvm,很多人感觉jvm离我们开发实际很远.但是,我们开发缺每时每刻都离不开jvm. a: java源码 编译后成.class字节码文件, b:根据classpath找到这个字节码文件, c ...
- 浅谈 G1 GC 日志格式
在 Java9 中,G1 GC 将成为默认的垃圾收集器,G1 垃圾收集器的关键特性之一是能够在不牺牲吞吐量的同时,限制 GC 暂停时间(即可以设置所需的最大停顿时间). 由于 G1 GC 正在逐渐成为 ...
- 浅谈JVM - 内存结构(二)- 虚拟机栈|凡酷
2.1 定义 Java Virtual Machine Stacks(Java虚拟机栈) Java 虚拟机栈描述的是 Java 方法执行的内存模型,用于存储栈帧,是线程私有的,生命周期随着线程启动而产 ...
随机推荐
- JS基础-数据类型判断typeof、instanceof、Object.prototype.toString
typeof用在基本数据类型和函数时,返回其对应类型的描述,对于引用类型都返回为object. instanceof无法判断基本数据类型,对于引用类型数据,返回其其对应类型. Object.proto ...
- 三年Android开发,竟只会增删改查,被面试官一顿怼!
最近看到某公司面试官发的这样一个帖子: 我面试了一个有三年Android开发经验的小伙子,也是我有史以来给别人面试时间最短的一次,不到十分钟就结束了,原因很简单,底子太差只会curd,很多技术性的问题 ...
- git 强制放弃本地修改(新增、删除文件)
本地修改了一些文件,其中包含修改.新增.删除的. 不需要了,想要丢弃,于是做了git check -- .操作,但是只放弃了修改的文件,新增和删除的仍然没有恢复. 于是百度了下,使用如下命令: git ...
- Python Flask API实现方法-测试开发【提测平台】阶段小结(一)
微信搜索[大奇测试开],关注这个坚持分享测试开发干货的家伙. 本篇主要是对之前几次分享的阶阶段的总结,温故而知新,况且虽然看起来是一个小模块简单的增删改查操作,但其实涉及的内容点是非常的密集的,是非常 ...
- Longhorn,企业级云原生容器分布式存储 - K8S 资源配置示例
内容来源于官方 Longhorn 1.1.2 英文技术手册. 系列 Longhorn 是什么? Longhorn 企业级云原生容器分布式存储解决方案设计架构和概念 Longhorn 企业级云原生容器分 ...
- noip30
T1 一眼看,觉得是个状压,然而又觉得不太行,去打暴力了,然而暴力都打挂的我biss. 正解: 还是暴力,考虑 \(meet \; in \; the \; middle\) 显然对于每个数,只有三种 ...
- Ubuntu的build-essential有什么作用
Ubuntu缺省情况下,并没有提供C/C++的编译环境,因此还需要手动安装.但是如果单独安装gcc以及g++比较麻烦,幸运的是,Ubuntu提供了一个build-essential软件包.查看该软件包 ...
- vue去掉一些烦人的校验规则
例如:括号前没有加空格报错,很难受 如何处理呢,故意犯错,然后打开页面出现错误信息,如下图复制错误 space-before-function-paren 找到项目中的.eslintrc.js 添加一 ...
- mybatis传入参数为0被误认为是空字符串的解决方法
在mbatis中使用Xml配置sql语句时,出现了这样一个问题.当我传入的参数为0去做判断时,mybatis会把参数0当成是空字符串去判断而引起查询结果错误 所以在做项目时一定要注意,用到MyBati ...
- Struts2与Hibernate整合
时间:2017-1-26 02:00 1.创建一个Web项目2.导入jar包 3.引入配置文件 struts.xml hibernate.cfg.xml log4j.prope ...