OopMap

前文我们说到,JVM 采用的可达性分析法有个缺点,就是从 GC Roots 找引用链耗时。

都说他耗时,他究竟耗时在哪里?

GC 进行扫描时,需要查看每个位置存储的是不是引用类型,如果是,其所引用的对象就不能被回收;如果不是,那就是基本类型,这些肯定是不会引用对象的;这种对 GC 无用的基本类型的数据非常多,每次 GC 都要去扫描,显然是非常浪费时间的。

而且迄今为止,所有收集器在 GC Roots 枚举这一步骤都是必须暂停用户线程的。

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

一个很自然的想法,能不能用空间换时间? 把栈上的引用类型的位置全部记录下来,这样到 GC 的时候就可以直接读取,而不用一个个扫描了。Hotspot 就是这么实现的,这个用于存储引用类型的数据结构叫 OopMap

OopMap 这个词可以拆成两部分:OopMapOop 的全称是 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 的安全点与安全区域的更多相关文章

  1. 浅谈jvm中的垃圾回收策略

    下面小编就为大家带来一篇浅谈jvm中的垃圾回收策略.小编觉得挺不错的,现在就分享给大家,也给大家做个参考.一起跟随小编过来看看吧   java和C#中的内存的分配和释放都是由虚拟机自动管理的,此前我已 ...

  2. 浅谈JVM内存模型

    JAVA虚拟机在执行JAVA程序的时候,会把它管理的内存分成若干不同的数据区域,每个区域都有各自的用途.目前大致把JVM内存模型划分为五个区域:程序计数器,虚拟机栈,本地方法栈,堆和方法区. 程序计数 ...

  3. 浅谈 JVM 结构体系、类加载、JDK JRE JVM 三者的关系

    一.java类,创建.编译.到运行的工程: 1.随便建一个Java类,保存后就是一个.java文件, 2.然后我们使用 javac命令编译 .java文件,生产 .class文件. 3.再然后使用 j ...

  4. 浅谈JVM线程调度机制及主要策略

    在之前有说过线程,应该都知道,所谓线程就是进程中的一个子任务,一个进程有多个线程.今天的话主要就是谈一谈JVM线程调度机制.我们结合线程来说,当我们在做多线程的案例时,如一个经典案例,火车站卖票. * ...

  5. 浅谈JVM垃圾回收

    JVM内存区域 要想搞懂啊垃圾回收机制,首先就要知道垃圾回收主要回收的是哪些数据,这些数据主要在哪一块区域. Java8和Java8之前的相同点有很多. 都有虚拟机栈,本地方法栈,程序计数器,这三个是 ...

  6. 浅谈JVM内存区域划分

    好吧,虽说真的有看过<深入分析Java Web技术内幕>一书,但当时看的时候还是一知半解,稀里糊涂的看完了.本来是打算暑假拿起来再看一遍的,但是早两天一个阿里学长给我做了个小面试,让我颇受 ...

  7. 浅谈jvm

    1 .说起jvm,很多人感觉jvm离我们开发实际很远.但是,我们开发缺每时每刻都离不开jvm. a: java源码 编译后成.class字节码文件, b:根据classpath找到这个字节码文件, c ...

  8. 浅谈 G1 GC 日志格式

    在 Java9 中,G1 GC 将成为默认的垃圾收集器,G1 垃圾收集器的关键特性之一是能够在不牺牲吞吐量的同时,限制 GC 暂停时间(即可以设置所需的最大停顿时间). 由于 G1 GC 正在逐渐成为 ...

  9. 浅谈JVM - 内存结构(二)- 虚拟机栈|凡酷

    2.1 定义 Java Virtual Machine Stacks(Java虚拟机栈) Java 虚拟机栈描述的是 Java 方法执行的内存模型,用于存储栈帧,是线程私有的,生命周期随着线程启动而产 ...

随机推荐

  1. C++调试总结

    一.参考: 本文主要参考<C++编程调试秘笈>一书. 在编写C++代码时,我们不应该自己捕捉缺陷,而是由编译器和可执行代码为我们做这些事情,该书便提供了这样的一个思考.作者以"调 ...

  2. 如何在 NetCore 中定义我们自己的JSON配置文件的管理器。

    一.介绍 微软已经对外提供了新的平台,我们叫它们是 Net Core 平台,这个平台和 Net Framework 平台有本质的区别,这个最本质的区别就是微软的C#代码可以跨平台了.当前我们主流的3大 ...

  3. Nginx 配置错误导致漏洞

    目录 1.CRLF注入漏洞 2.目录穿越漏洞 参考链接 1.CRLF注入漏洞 CRLF是"回车+换行"(\r\n)的简称,其十六进制编码分别为0x0d和0x0a.先看payload ...

  4. 腾讯技术团队整理,为什么 Flutter 能最好地改变移动开发

    导语 | Flutter 框架是当下非常热门的跨端解决方案,能够帮助开发者通过一套代码库高效构建多平台精美应用,支持移动.Web.桌面等多端开发.但仍然有很多产品.设计.甚至开发同学并不了解 Flut ...

  5. Python对系统数据进行采集监控——psutil

    大家好,我是辰哥- 今天给大家介绍一个可以获取当前系统信息的库--psutil 利用psutil库可以获取系统的一些信息,如cpu,内存等使用率,从而可以查看当前系统的使用情况,实时采集这些信息可以达 ...

  6. 零基础学Java之Java学习笔记(一):Java概述

    什么是Java? Java是一门面向对象编程语言,可以编写桌面应用程序.Web应用程序.分布式系统和嵌入式系统应用程序. Java特点有哪些? 1.Java语言吸收了C++语言的各种优点,具有功能强大 ...

  7. Java之JSP

    JSP JSP简介 JSP指的是 JavaServerPages ,Java服务器端页面,也和Servlet一样,用来开发动态web JSP页面中可以嵌入java代码为用户提供动态数据 JSP原理 J ...

  8. SSRF详解

    上一篇说了XSS的防御与绕过的思路,这次来谈一下SSRF的防御,绕过,利用及危害 0x01 前置知识梳理 前置知识涉及理解此漏洞的方方面面,所以这部分要说的内容比较多 SSRF(Server-Side ...

  9. ARM—异常中断处理

    文章目录 一. ARM程序执行流程 二. ARM工作模式 三. ARM中异常中断的种类 四. 异常中断向量表及优先级 五. 异常中断用到的寄存器 六. ARM进入处理异常中断时的操作 七. ARM退出 ...

  10. noip13

    T1 一开始直接丢了个暴力走人50pts,然后开始打表找规律,啥也没找着,最后二十分钟突然看出来了什么,把 \(f_{n,m}\)式子列了一下,发现常数项没啥规律,最后五分钟,突然闪过一丝灵感,但是是 ...