作为使用范围最广的虚拟机之一HotSpot,必须对垃圾回收算法的执行效率有严格的考量,只有这样才能保证虚拟机高效运行

枚举根节点

从可达性分析中从 GC Roots 节点找引用链这个操作为例,可以作为 GC Roots 的节点主要在全局性的引用(例如常量或者类静态属性)与执行上下文(例如栈帧中的本地变量表)中。

但是现在很多应用仅仅方法区就有数百兆,如果要逐个检查这里面的引用,那么必然会消耗很多的时间。

另外,可达性分析对执行时间的敏感还体现在 GC 停顿上,因为这项分析工作必须在一个能确保一致性的快照中进行 —— 这里的“一致性”指的是在整个分析过程中整个执行系统看起来就像是被冻结在某个时间点上,不可以出现分析过程中对象引用关系还在不停变化的情况,该点不满足的话分析结果准确性就无法得到保证。

这点是导致 GC 进行时必须停顿所有 Java 执行线程的其中一个重要原因,即使是号称不会发生停顿的 CMS 收集器中,枚举根节点也是必须要停顿的。

由于目前主流 Java 虚拟机使用的都是准确式 GC,所以当执行系统停顿下来后,并不需要一个不漏的检查完成所有执行上下文和全局的引用位置,虚拟机应当是有办法直接得知那些地方存放着对象引用的。 在HotSpot的实现中,是使用一组被称为OopMap的数据结构来达到这个目的的,在类加载的时候,HotSpot就把对象内什么偏移量上是什么类型的数据计算出来,在JIT 编译过程中,也会在特定的位置记录下栈和寄存器中哪些位置是引用。这样, GC 在扫描时就可以直接得知这些信息了。

安全点

在 OopMap 的帮助下,HotSpot 可以快速并且准确的完成 GC Roots 枚举,但是一个很现实的问题随之而来:可能导致引用关系变化,或者说 OopMap 内容变化的指令非常多,如果为每一条指令都生成对应的 OopMap,那么将需要大量的额外空间,这样 GC 的空间成本将会变得很高。

实际上,HotSpot 也的确没有为每一条指令都生成 OopMap,只是在“特定的位置” 记录了这些信息,这些位置被称为是安全点,即程序执行时并非是在所有地方都能停顿下来开始 GC ,只有到达安全点时才能暂停。

安全点的选择既不能太少以至于让 GC 等待太长时间,也不能过于频繁以至于过分增大运行时负荷。

所以,安全点的选定基本上是以程序“是否具有让程序长时间执行的特征”为标准进行选定的——因为每条指令执行的时间都非常短暂,程序不太可能因为指令流长度太长这个原因而过长时间运行,“长时间执行”的最明显特征就是指令序列复用,例如方法调用、循环跳转、异常跳转等,所以具有这些功能的指令才会产生安全点。

对于安全点,另一个需要考虑的问题就是如何让 GC 发生时让所有线程(这里不包括执行 JNI 调用的线程)都“跑”到最近的安全点再停顿下来。这里有两种方案可供选择:抢先式中断和主动式中断。

  • 抢先式中断:无需线程的执行代码主动配合,在 GC 发生时,首先把所有线程全部中断,如果发现有线程中断的地方不再安全点上,就会发线程,让它“跑”到安全点上。现在几乎没有虚拟机实现采用抢先式中断来暂停线程从而响应GC事件
  • 主动式中断:当 GC 需要中断线程时,不直接对线程操作,仅仅简单地设置一个标志,各个线程执行时主动去轮询这个标志,发现中断标志为真时就自己中断挂起。轮询标志的地方和安全点是重合的,另外再加上创建对象需要分配内存的地方。

安全区域

使用安全点似乎已经完美解决了如何进入 GC 的问题,但实际情况却并不一定,安全点机制保证了程序执行,在不太长的时间内就会遇到可以进入 GC 的安全点。

但是线程“不执行”的时候呢?所谓不执行就是没有分配 CPU 时间,典型的例子就是线程处于 Sleep 状态或者 Blocked状态,这时候线程无法响应 JVM 的中断请求,“走”到安全点去中断挂起,JVM显然也不太可能等待线程重新被分配 CPU 时间。对于这种状况,就需要安全区域来解决。

安全区域就是在一段代码片段中,引用关系不会发生变化,在这个区域中的任意地方开始 GC 都是安全的。

在线程执行到安全区域中的代码时,首先标识自己已经进入了安全区域,那样,当这段时间里 JVM 要发起 GC 时,就不用管标识自己为安全区域状态的线程了。

当线程要离开安全区域时,它要检查系统是否已经完成了根节点枚举(或者是整个 GC 过程),如果完成了,那线程就继续执行,否则它就必须等待直到收到可以安全离开安全区域的信号为止。

HotSpot 虚拟机垃圾回收算法实现的更多相关文章

  1. HotSpot的垃圾回收算法

    这系列文章只简单介绍一下HotSpot垃圾回收中涉及到的算法及相关的垃圾回收器,并不进行源代码分析,后面会开一个系列对HotSpot的垃圾回收以及内存管理进行源代码解读. 涉及到的垃圾回收算法一共有 ...

  2. JAVA虚拟机垃圾回收算法原理

    除了释放不再被引用的对象外,垃圾收集器还要处理堆碎块.新的对象分配了空间,不再被引用的对象被释放,所以堆内存的空闲位置介于活动的对象之间.请求分配新对象时可能不得不增大堆空间的大小,虽然可以使用的总空 ...

  3. java虚拟机-垃圾回收算法

    在Java中,程序员不需要去关心内存动态分配和垃圾回收的问题,这一切都交给了JVM来处理.但是首先需要明确,什么样的对象才能当为垃圾: 1.引用计数法:如果某个引用(即指针)指向对象,那么说明该对象还 ...

  4. 【译】Java SE 14 Hotspot 虚拟机垃圾回收调优指南

    原文链接:HotSpot Virtual Machine Garbage Collection Tuning Guide,基于Java SE 14. 本文主要包括以下内容: 优化目标与策略(Ergon ...

  5. Java虚拟机—垃圾回收算法(整理版)

    1.概述 由于垃圾收集算法的实现涉及大量的程序细节.因此本节不打算过多地讨论算法的实现,只是介绍几种算法的思想及其发展过程.主要涉及的算法有标记-清除算法.复制算法.标记-整理算法.分代收集算法. 2 ...

  6. 了解java虚拟机—垃圾回收算法(5)

    引用计数器法(Reference Counting) 引用计数器的实现很简单,对于一个对象A,只要有任何一个对象引用了A,则A的引用计数器就加1,当引用失效时,引用计数器减1.只要对象A的引用计数器的 ...

  7. 深入理解java虚拟机【垃圾回收算法】

    Java虚拟机的内存区域中,程序计数器.虚拟机栈和本地方法栈三个区域是线程私有的,随线程生而生,随线程灭而灭:栈中的栈帧随着方法的进入和退出而进行入栈和出栈操作,每个栈帧中分配多少内存基本上是在类结构 ...

  8. (转)《深入理解java虚拟机》学习笔记3——垃圾回收算法

    Java虚拟机的内存区域中,程序计数器.虚拟机栈和本地方法栈三个区域是线程私有的,随线程生而生,随线程灭而灭:栈中的栈帧随着方法的进入和退出而进行入栈和出栈操作,每个栈帧中分配多少内存基本上是在类结构 ...

  9. Java虚拟机运行时数据区域及垃圾回收算法

    程序计数器 记录正在执行的虚拟机字节码指令的地址(如果正在执行的是本地方法则为空). Java 虚拟机栈 每个 Java 方法在执行的同时会创建一个栈帧用于存储局部变量表.操作数栈.动态链接.方法出口 ...

随机推荐

  1. MIP 与 AMP 合作进展(3月7日)

    "到目前为止,全网通过 MIP 校验的网页已超10亿.除了代码和缓存, MIP 还想做更多来改善用户体验移动页面." 3月7日,MIP 项目负责人在首次 AMP CONF 上发言. ...

  2. 鸟哥的Linux私房菜笔记第四章

    前言 对着<鸟哥的Linux私房菜-基础版>做了简化笔记.不想让自己知其然而不知其所然.所以写个博客让自己好好巩固一下,当然不可能把书中的内容全部写下来.在这里就简化一点把命令写下来. 让 ...

  3. 聊聊 JUC 并发包

    今天开始我们聊聊 Java 并发工具包中提供的一些工具类,本文主要从并发同步容器和并发集合工具角度入手,简单介绍下相关 API 的用法与部分实现原理,旨在帮助大家更好的使用和理解 JUC 工具类. 在 ...

  4. Android Gradle defaultConfig详解及实用技巧

    实际项目中,都会应用Android Gradle Plugin,根据实际中的项目模块的职责,可以具体应用如下四种插件类型. 1,apply plugin: 'com.android.applicati ...

  5. .NET(C#、VB)APP开发——Smobiler平台控件介绍:SignatureButton控件

    SignatureButton控件 一.          样式一 我们要实现上图中的效果,需要如下的操作: 从工具栏上的"Smobiler Components"拖动一个Sign ...

  6. Java集合 - List介绍及源码解析

    (源码版本为 JDK 8) 集合类在java.util包中,类型大体可以分为3种:Set.List.Map. JAVA 集合关系(简图) (图片来源网络) List集合和Set集合都是继承Collec ...

  7. 记ibatis使用动态列查询问题(remapresults)

    今天在项目开发中,遇到了一个问题:使用ibatis 动态查询列时,每次返回的结果列都是第一次查询的结果列,然而控制台执行的SQL语句时包含该结果列的.比如: <select id="g ...

  8. PowerDesigner制作UMI图

    首先我们要下载一个PowerDesigner,自己上百度下载哈!嘻嘻!!! 我这个是汉化版的 然后点这个,再到空白的地方点一下就创建好了. 然后单击右边箭头然后双击 不管是制作的图还是代码生成的图都可 ...

  9. GreenDao的初次使用--号称Android最快的关系型数据库

    一.准备工作 1.项目build.gradle文件下的dependencies中引入插件: classpath 'org.greenrobot:greendao-gradle-plugin:3.2.1 ...

  10. 【English】20190428

    It is of paramount importance that极为重要的一点[pærəmaʊnt] strategizing around SOA围绕soa制定战略  efficient gov ...