hotspot的安全区(saferegion)和安全点(safepoint)
1、通过OopMap完成根节点枚举
HotSpot虚拟机使用可达性分析算法确定对象是否可以被GC。
可达性分析算法从一系列GCRoot对象开始,向下搜索引用链,如果一个对象没有与任何GCRoot对象关联,这个对象就会被判定为可回收对象。
GCRoot包括以下对象:
虚拟机栈上的本地变量表引用的对象
方法区中类的静态属性引用的对象
方法区中常量引用的对象
本地方法栈中JNI引用的对象
这一过程称为根节点枚举,也就是垃圾回收中的标记过程,当前所有的垃圾收集器,在标记阶段都必须停止所有java执行线程(STW),以保证对象引用状态不会发生变化。
HotSpot虚拟机作为准确式虚拟机,维护了一个专门的映射表(OopMap)记录哪些位置存放着对象引用,来快速完成根节点枚举过程。
类加载完成,HotSpot就会把对象内某个偏移位置是否为对象引用记录下来,JIT编译过程中,也会在特定的位置记录下栈和局部变量表中哪些位置是引用。
2、安全点SafePoint
为每一个操作记录OopMap不现实,HotSpot虚拟机引入了SafePoint。安全点就是某些记录线程此时调用栈、寄存器等一些重要的数据区域里什么地方包含了GC要管理的指针(对象引用),而这些对象引用是通过OopMap结构进行记录的,可以直接通过对OopMap结构的访问来获得对象的引用。
SafePoint是程序中的某些位置,线程执行到这些位置时,线程中的某些状态是确定的,在safePoint可以记录OopMap信息,线程在safePoint停顿,虚拟机进行GC。一个线程可以在SafePoint上,也可以不在SafePoint上。一个线程在SafePoint时,它的状态可以安全地被其他JVM线程所操作和观测。
线程停顿方式有两种,抢先式中断和主动式中断:
抢先式中断:虚拟机需要GC时,中断所有线程,让没有到达SafePoint的线程继续执行至SafePoint并中断
主动式中断:虚拟机不直接中断线程,而是在内存中设置标志位,线程检查到标志位被设置,运行至SafePoint时主动中断
hotspot采用的是第一种, 也就是主动检测的方式. 而在主动检测的方式中又分为两种方式:
- 指定点执行检测代码
- polling page访问异常触发
Hotspot, 顾名思义, 就是热点的意思, 这里所谓的热点指的是热点代码, 也就是执行频率很高的代码, hotspot会根据运行时的信息来统计, 并将高频率执行的java字节码直接翻译成本地代码, 由此提高执行效率. 因此, hotspot有两种执行方式, 一个是解释执行, 一个是编译执行。指定点检测主要是解释执行用的,对于需要高效实现的地方,则采用polling page。
polling page和普通物理页面没什么区别,需要safepoint时, 会修改该页面的权限为不可访问, 这样编译的代码在访问这个页面时, 会触发段违规异常(SEGEV). 而hotspot在启动时捕获了这个异常, 当意识到是访问polling page导致时, 则主动挂起。
SafePoint一般出现在以下位置:
循环体的结尾
方法返回前
调用方法的call之后
抛出异常的位置
这些位置保证线程不会长时间运行而无法到达SafePoint,避免其他线程都停顿等待本线程。
public static void main(String[] args) throws Exception { [1]DemoObject demoObject = new DemoObject(); [2]//往demoObject上挂一个字符串对象 [3]demoObject.val1 = "this is a string object"; [4]Thread.sleep(1000000); }
我们知道代码是在线程里执行的, GC的代码也是在线程里执行, 如果执行GC的时候其他线程也同时执行的话, heap的状态将是难以追踪的. 以上面的代码为例, 假设GC线程通过扫描线程的stack(线程stack是一种GC Root), 扫描到demoObject, 然后根据这时候, main函数执行到[3], 但还未执行, 扫描的结果只发现demoObject是存活的, 接下来, main函数的线程执行[3], demoObject.val1引用了一个字符串对象, 这个对象的扫描就漏掉了, 除非以某种方式记录下这个变化, 然后重新扫描demoObject. 即便有办法记录这个赋值导致的变化然后再次扫描, 如果其他线程这时候又来捣乱, 那么重新扫描的时候有可能又发生了变化, 陷入循环…
再往下一点, 我们知道CPU执行运算时的数据, 需要从内存里载入寄存器中, 运算完再从寄存器存入内存, 对象的地址也要经过这么个过程. 假如一个java线程分配了一个对象A, 该对象的地址存在某个寄存器中, 然后线程的cpu时间片到期被切换出去, 同时GC的线程开始扫描存活对象, 由于没有路径到这个地址还在寄存器中的对象, 这个对象被认为是garbage, 回收了. 然后睡眠的java线程醒来了, 把寄存器中的对象地址赋值给了存活对象的某个字段, over…
GC的目的在于帮助我们收集不再使用的内存, 但是把正在是使用的内存当成垃圾回收显然是不能接受的. 同时通过分析也看到, 由于多线程运行环境的存在, GC的工作会变的异常复杂, 要安全的回收垃圾, 需要具备两个条件:
heap的变化是受限的, 当然了, 所有线程都停下来最好, 这样heap 在GC过程中是稳定的,这是最简单的情况.
heap的状态是已知的, 不会有活着的对象找不到或者很难找的情况. 想想对象地址在寄存器中的情况, 虽然可以有办法可以扫描线程的寄存器, 即使这样, 也必须知道哪个寄存器在某个时刻存的是地址, 要做到扫描不漏是很复杂的事情.
3、安全区SafeRegion
SafePoint无法解决线程未达到SafePoint并处于休眠或等待状态的情况,此时引入SafeRegion的概念。
SafeRegion是代码中的一块区域或线程的状态,在SafeRegion中,线程执行与否不会影响对象引用的状态。线程进入SafeRegion会给自己加标记,告诉虚拟机可以进行GC;线程准备离开SafeRegion前会询问虚拟机GC是否完成。
参考文章:
(1)聊聊JVM(六)理解JVM的safepoint https://blog.csdn.net/ITer_ZC/article/details/41847887
(2)聊聊JVM(九)理解进入safepoint时如何让Java线程全部阻塞 https://blog.csdn.net/ITer_ZC/article/details/41892567
hotspot的安全区(saferegion)和安全点(safepoint)的更多相关文章
- 虚拟机研究系列-「GC本质底层机制」SafePoint的深入分析和底层原理探究指南
SafePoint前提介绍 在高度优化的现代JVM里,Safepoint有几种不同的用法.GC safepoint是最常见.大家听说得最多的,但还有deoptimization safepoint也很 ...
- JVM(四)垃圾回收的实现算法和执行细节
全文共 1890 个字,读完大约需要 6 分钟. 上一篇我们讲了垃圾标记的一些实现细节和经典算法,而本文将系统的讲解一下垃圾回收的经典算法,和Hotspot虚拟机执行垃圾回收的一些实现细节,比如安全点 ...
- JVM自动内存管理:对象判定和回收算法
可回收对象的判断方法 1.引用计数算法 2.可达性分析算法 引用计数算法 给对象中添加一个引用计数器,每当有一个地方引用它时,计数器值就加1:当引用失效时,计数器值就减1:任何时刻计数器为0的对象就是 ...
- 没有二十年功力,写不出Thread.sleep(0)这一行“看似无用”的代码!
你好呀,我是喜提七天居家隔离的歪歪. 这篇文章要从一个奇怪的注释说起,就是下面这张图: 我们可以不用管具体的代码逻辑,只是单单看这个 for 循环. 在循环里面,专门有个变量 j,来记录当前循环次数. ...
- 接口偶尔超时,竟又是JVM停顿的锅!
原创:扣钉日记(微信公众号ID:codelogs),欢迎分享,转载请保留出处. 简介 继上次我们JVM停顿十几秒的问题解决后,我们系统终于稳定了,再也不会无故重启了! 这是之前的文章:耗时几个月,终于 ...
- HotSpot的算法实现
1.枚举根节点 可达性分析中从GC Roots节点找引用,可作为GC Roots的节点主要是全局性的引用与执行上下文中,如果要逐个检查引用,必然消耗时间.另外可达性分析对执行时间的敏感还体现在GC停顿 ...
- Hotspot GC实现原理
GC扫描 可达性分析的GC Roots主要是全局性引用或在Stack Frame中 ,现在的应用仅仅方法区往往就有几百兆,这样要这个检查这里面的引用,就必然会消耗很多时间,效率很低. 分析工作在一个保 ...
- 5.HotSpot的算法实现
1.枚举根节点 在可达性分析中,可以作为GC Roots的节点有很多,但是现在很多应用仅仅方法区就有上百MB,如果逐个检查的话,效率就会变得不可接受. 而且,可达性分析必须在一个一致性的快照中进行-即 ...
- [Inside HotSpot] C1编译器工作流程及中间表示
1. C1编译器线程 C1编译器(aka Client Compiler)的代码位于hotspot\share\c1.C1编译线程(C1 CompilerThread)会阻塞在任务队列,当发现队列有编 ...
随机推荐
- Java基础篇(中)
4.Java 关键字 下面列出了 Java 关键字.这些保留字不能用于常量.变量.和任何标识符的名称. 类别 关键字 说明 访问控制 private 私有的 protected 受保护的 public ...
- 基于python的图像傅里叶处理
import numpy as npimport matplotlib.pyplot as plt x = np.linspace(-10, 10, 1000)a = np.cos(x)b = a + ...
- 2019 找钢网java面试笔试题 (含面试题解析)
本人5年开发经验.18年年底开始跑路找工作,在互联网寒冬下成功拿到阿里巴巴.今日头条.找钢网等公司offer,岗位是Java后端开发,因为发展原因最终选择去了找钢网,入职一年时间了,也成为了面试官 ...
- elementUI 2个输入框 时间区间月份选择
<!DOCTYPE html> <html lang="en"> <head> <meta charset="UTF-8&quo ...
- Vue学习之基础及部分指令小结(一)
一.理解MVC和MVVM的关系: MVC:Model View Controller (模型 视图 控制器) 分别为:业务逻辑.界面.用来调度View和Model层 MVVM:Model View V ...
- Java 之 异常的处理
Java 异常处理的五个关键字:try.catch.finally.throws.throw 一.捕获异常 try...catch 如果异常出现的话,会立刻终止程序,所以我们得处理异常. try... ...
- Java集合学习(4):HashTable
一.概述 和HashMap一样,Hashtable也是一个散列表,它存储的内容是键值对. Hashtable在Java中的定义为: public class Hashtable<K,V> ...
- 记录SQLAlchemy的基本使用
代码 # -*- coding: utf-8 -*- from sqlalchemy import Column, String, create_engine from sqlalchemy.orm ...
- linux日志详解-摘录
小编言:会看Linux日志是非常重要的,不仅在日常操作中可以迅速排错,也可以快速的定位.` Liunx的配置文件在/etc/rsyslog.d里,可以看到如下信息这里的意思是将不通的所有优先级的信息输 ...
- 离线安装python的ibm_db模块
目前手头的项目是一个UI自动化框架,其中有些模块的功能需要与DB2数据库交互,于是百度了一下python操作DB2的模块是 ibm_db. 然而我的工作机器是一台windows堡垒机,不能联网,固不能 ...