低延迟垃圾收集器

低延迟垃圾收集器,即将最小停顿时间作为主要目标的垃圾收集器。本文主要介绍Shenandoah收集器。

衡量垃圾收集器的指标

衡量垃圾收集器的三项重要指标是:内存占用、吞吐量和延迟,三者构成了一个不可能三角,即三者的总体表现会随着软硬件技术的进步而提升,但三个方面几乎不可能同时达到完美,一款优秀的收集器通常最多可同时做好其中两项。

随计算机硬件的发展和性能的提升,我们越来越能容忍垃圾收集器多占用一些内存,同时硬件性能的提升对软件的处理能力有直接助益,硬件的规格和性能的提高有助于降低收集器运行时对应用程序的影响,使得吞吐量更高。而对于延迟则会带来负面效果,虚拟机要回收的内存越大,消耗时间就越多,在这种条件下,延迟会成为目前垃圾收集器最被重视的性能指标。

Shenandoah收集器

Shenandoah收集器与G1收集器相似,二者有着许多相似之处

  • 相似的堆内存布局:二者都使用基于Region的堆内存布局,且有着用于存放大对象的Humongous Region。
  • 相同的回收策略:二者都优先处理回收价值最大的Region。
  • 相似的思路:在初始标记、并发标记等阶段的思路都高度一致,甚至直接共享了一部分代码。

相比G1收集器Shenandoah在堆内存管理上的改进

Shenandoah与G1在堆内存管理上至少有三个明显的不同之处

  • Shenandoah在垃圾回收阶段并发,G1在垃圾回收阶段并行。
  • Shenandoah默认不使用分代收集,G1保留分代收集理论,每个Region都可以按需扮演新生代或老年代。
  • Shenandoah使用名为连接矩阵的全局数据结构记录跨Region引用关系,G1使用哈希表的局部数据结构记录跨Region引用关系。(Shenandoah默认不使用分代收集并非意味着分代收集对于Shenandoah没有价值,只是处于性价比权衡,分代收集的实现优先级较低)

下文将着重介绍Shenandoah的并发与连接矩阵以及实现思想

连接矩阵

在G1收集器中记忆集实现复杂,需要耗费10%~20%的堆容量维持收集器工作,Shenandoah摒弃了这种消耗大量内存和计算资源的记忆集,改用连接矩阵。

连接矩阵可以简单理解为一张二维表格(二维数组),如果Region N有对象指向Region M内的对象,就在表格的N行M列中标记。

连接矩阵示意图如下:

连接矩阵是一种全局数据结构,不需要像G1的记忆集实现一样每个Region单独计算维护。使用连接矩阵降低了处理跨Region指针时的记忆集维护消耗,也降低了伪共享发生的概率。

Shenandoah收集流程

收集流程可以大致划分为以下九个阶段

  • 初始标记(Initial Marking):标记与GC Roots直接关联的对象,此阶段需要暂停用户线程,暂停时间与堆大小无关,只与GC Roots数量相关。
  • 并发标记(Concurrent Marking):遍历对象图,标记出全部可达的对象,此阶段与用户线程并发,时间长短取决于存活对象数与对象图结构复杂度。
  • 最终标记(Final Marking):处理剩余的SATB(原始快照)扫描,并统计出回收价值最高的Region,并将这些Region构成本次垃圾回收的回收集,此阶段也有短暂的用户线程暂停。
  • 并发清理(Concurrent Cleanup):清理一个存活对象都找不到的Region。
  • ***并发回收(Concurrent Evacuation)***:此阶段要把回收集中存活的对象先复制到未被使用的Region中,此步骤需要两步以保证后续的正常访问,第一步将对象复制到新地址中,第二步再将指向被复制对象的引用改为新地址。此阶段不同于其他垃圾收集器,Shenandoah不会冻结用户线程,因此在对象移动的同时,用户线程仍然会不断的对被移动的对象进行访问,而修改引用为新地址的动作又很难一瞬间全部完成,为了避免垃圾回收过程中用户线程可能访问到旧地址的问题,Shenandoah使用了读屏障和"Brooks Pointers"转发指针。此阶段的运行时间长短取决于回收集的大小。
  • 初始引用更新(Initial Update Reference):创建一个线程集合点,确保所有并发回收阶段中进行收集行为的线程都已完成分配给他们的对象移动任务。此阶段耗时很短,会产生一个非常短暂的停顿。
  • 并发引用更新(Concurrent Update Reference):将堆内存中所有指向旧对象的引用修正为复制后的新地址,此操作只需要按照内存物理地址的顺序,线性地搜索出引用类型,旧值改为新值即可。此阶段并发,时间长短取决于涉及到的引用数量多少。
  • 最终引用更新(Final Update Reference):和并发引用更新目的一样,只是将目标从堆换成GC Roots,此阶段需要停顿,时间与GC Roots数量相关。
  • 并发清理(Concurrent Cleanup):经过此前的一系列操作,回收集中便已再无存活对象,所有对象都变变为了此前提及的Immediate Garbage Region,直接回收全部回收集中的Region即可。

以上九个阶段中,最为重要,也最能体现Shenandoah思想的是并发标记、并发回收和并发引用更新三个阶段。Shenandoah垃圾回收流程图如下

图注:
图源自(https://shipilev.net/talks/devoxx-Nov2017-shenandoah.pdf)
其中
——黄色区域表示被选入回收集的Region
——绿色区域表示还存活的对象
——蓝色区域表示用户线程可用来分配对象的内存Region
——橘色区域表示回收集中存活对象复制到的Region
图片下方流程中的红色竖线表示用户线程暂停

转发指针

作用

转发指针用来实现对象移动与用户线程并发。

实现

在使用转发指针解决此问题之前,想要做类似并发的操作,通常需要在被移动对象的内存上设置内存保护陷阱,当用户线程访问到归属于旧对象的内存空间便会产生中断自陷,进入预设好的异常处理器中,再由其中的代码逻辑将访问转发到复制后的新对象上。如果没有操作系统的支持,这种解决方案会导致用户态频繁切换为核心态(操作系统的两种内核模式),代价非常大,不能频繁使用。

转发指针不需要内存保护陷阱,解决方案在原有对象布局结构的最前面统一增加一个新的引用字段,在不处于并发移动状态下,该引用指向自己,在处于并发移动状态下,该引用指向新地址。

转发指针示意图如下

缺点

1)如果不加保护措施,可能会出现写操作发生在旧地址对象身上

收集器处理存活对象时,会有两个操作,分别为
收集器线程复制新的对象副本到新地址(事件1)
收集器线程更新转发指针的引用值为新地址(事件2)
同时,用户线程可能会更新目标对象的某字段(事件3)

由于收集器线程与用户线程是并发执行的,那么就有可能发生,事件3在事件1和事件2之间执行,这样就会导致用户线程对对象的更新发生在了旧对象身上。

针对这种情况,必须对转发指针的访问操作采取同步措施,保证收集器线程(即事件1,2)和用户线程(即事件3)只有其中之一能执行,另一个必须等待,避免二者交替进行。Shenandoah通过比较并交换(CAS)操作来保证并发时对象访问的正确性。

2)额外转向开销和执行频率过高

转发指针与句柄定位相似,二者都是间接性的对象访问方式,区别在于句柄通常统一存放在句柄池,而转发指针分散存放在每个对象头之前。同样,转发指针也有间接对象访问技术的通病——每次对象访问都会有一次额外转向开销。

虽然这个转发开销已经被优化到了一行汇编指令的程度,但由于转发指针是保证并发时旧对象与新对象访问的一致性,而对象访问的涵盖范围极广,且使用频繁,因此执行成本仍不能忽略,只是转发指针相较内存保护陷阱已经好了很多。

为了实现转发指针,Shenandoah在读、写屏障中都加入了额外的转发处理,相较写屏障,读屏障的代价更大,因为代码中读取出现的频率比写入出现的频率高很多,读屏障的数量自然也比写屏障多得多,因此读屏障不允许任何重量级操作。

为了缓解数量庞大的读屏障会带来许多额外的性能开销,开发者计划在JDK13中将Shenandoah内存屏障模型改进为基于引用访问屏障的实现,基于引用访问屏障就是指内存屏障只会拦截对象中数据类型为引用类型的读写操作,而不会去拦截原生数据类型等非引用类型的读写,这样能够省去大量原生类型、对象比较、对象加锁等场景中设置内存屏障带来的消耗。

Shenandoah收集器的简单总结

  • Shenandoah的强项在于低延迟,相应的,由于高运行负担,吞吐量成为了Shenandoah的弱项。
  • 在堆内存布局上和垃圾回收过程部分阶段实现思路与G1收集器高度相似。
  • 在堆内存布局上,采用了基于Region的内存布局,有着用于存放大对象的Humongous Region,但与G1收集器不同,Shenandoah没有引入分代收集理论。
  • 在记忆集实现上,Shenandoah采用了名为连接矩阵的全局数据结构记录跨Region引用关系,相较G1降低了处理跨Region引用时记忆集的维护消耗,同时降低了伪共享发生的概率。
  • 在垃圾回收过程中,Shenandoah实现了大部分时间垃圾收集线程都能够与用户线程并发,垃圾回收算法思路采用标记-复制算法。
  • 引入转发指针解决收集线程与用户线程并发时遇到的问题。

参考书籍 《深入理解Java虚拟机》第三版 ——周志明
本篇内容主要用于作者自身学习总结记录,才疏学浅,如文中出现纰漏,还望指正

JVM学习笔记(九)———Shenandoah垃圾收集器相关推荐

  1. JVM学习笔记-03-类加载器及双亲委派机制

    JVM学习笔记-03-类加载器及双亲委派机制 文章目录 JVM学习笔记-03-类加载器及双亲委派机制 1. 类加载器 视频链接-最新JVM教程IDEA版[Java面试速补篇]-03-类加载器及双亲委派 ...

  2. JVM学习笔记(二):垃圾收集

    程序计数器. 虚拟机栈. 本地方法栈3个区域随线程而生,随线程而灭:栈中的栈帧随着方法的进入和退出而有条不紊地执行着出栈和入栈操作. 每一个栈帧中分配多少内存基本上是在类结构确定下来时就已知的,因此这 ...

  3. JVM学习笔记二 :垃圾收集的过程分析Eden-Survivor-Tenured

    内存申请过程 JVM会试图为相关Java对象在Eden中初始化一块内存区域: 当Eden空间足够时,内存申请结束.否则到下一步: JVM试图释放在Eden中所有不活跃的对象(minor collect ...

  4. 深入理解JVM读书笔记二: 垃圾收集器与内存分配策略

    3.2对象已死吗? 3.2.1 引用计数法 给对象添加一个引用计数器,每当有一个地方引用它的地方,计数器值+1:当引用失效,计数器值就减1;任何时候计数器为0,对象就不可能再被引用了. 它很难解决对象 ...

  5. jvm学习 Shenandoah垃圾收集器

    系统学习请点击jvm学习目录 建议学习Shenandoah之前先学习G1垃圾收集器 前言 Shenandoah垃圾收集器是一个很有意思的垃圾收集器,它是第一款非Oracle公司开发的HotSpot垃圾 ...

  6. JVM学习笔记(四)

    JVM学习笔记(四) 文章目录 JVM学习笔记(四) 笔记链接 1.GC算法 1.1GC-判断对象是否可回收 1.1.1 引用计数法 1.1.1 可达性分析 1.2GC-回收算法 标记清除法(Mark ...

  7. jvm学习笔记(三)

    jvm学习笔记(三) 文章目录 jvm学习笔记(三) 1.全部笔记链接 2.堆 2.1堆的划分 使用JVM参数查看划分 Hotspot堆内存划分图(JDK8之前) 2.2 GC对堆的回收 GC的种类 ...

  8. jvm学习笔记(二)

    jvm学习笔记(二) 文章目录 jvm学习笔记(二) 1.全部笔记链接 2. Native关键字 3.关于JVM规范 3.1 JVM规范中运行时数据区的概念 4.HotSpot的JVM运行时数据区 4 ...

  9. 【JVM学习笔记】内存回收与内存回收算法 就哪些地方需要回收、什么时候回收、如何回收三个问题进行分析和说明

    目录 一.相关名词解释 垃圾收集常用名词 二.哪些地方需要回收 本地方法栈.虚拟机栈.程序计数器 方法区 Java堆 三.什么时候回收 1. 内存能否被回收 内存中的引用类型 引用计数算法 可达性分析 ...

  10. JVM学习笔记汇总:结合尚硅谷宋红康老师视频教程及PPT

    JVM学习笔记汇总:结合尚硅谷宋红康老师视频教程及PPT 第一章:JVM虚拟机的介绍 1.1虚拟机的分类 虚拟机通常分为两类:系统虚拟机和程序虚机.其中,系统虚拟机是指完全对物理计算机的仿真,而程序虚 ...

最新文章

  1. OpenCV中图像旋转(warpAffine)算法的实现过程
  2. bzoj3171: [Tjoi2013]循环格(费用流)
  3. mxd 对象继承法则
  4. boost::range_reverse_result_iterator相关的测试程序
  5. 卧槽,柠檬也能做汽车???
  6. 打印1-400以内 能同时被5和9 整数的数将这些数放入一个列表中,再输出这个列表
  7. mysql数据应用从入门_MYSQL数据库应用从入门到精通----读书笔记
  8. 这可能是目前最好的图像超分辨率算法,刚刚开源了
  9. 学会智能标注与海量复杂文本分类
  10. AD10 PCB等长布线----蛇形布线
  11. mdf2iso linux,MDF to ISO下载
  12. 云筑网认证_云筑网供应商常见问题.doc
  13. JAVA爬取网站查询网络IP所在地
  14. 如何用计算机表白男神,女生表白男生的方法 教你如何正确向男神表白
  15. 18.ARP报文格式详解
  16. 3DsMax导出插件编写(二)——常规SDK方法进行信息获取和保存文件
  17. 中国已消失的 9 所世界级大学
  18. 零基础学摄影nbsp;人像摄影调节光…
  19. 修改win10 ntp服务器地址,修改win10 ntp服务器地址
  20. Perseus(擎天):统一深度学习分布式通信框架

热门文章

  1. excel冻结窗口怎么设置_kodi怎么设置中文?kodi如何设置窗口化
  2. Linux文件命令精通指南(二)(转)
  3. 痞子衡嵌入式:分享一个i.MXRT系列配套DRAM压力测试上位机工具(i.MXRT DRAM Tester)...
  4. java计算机毕业设计面向企业人力资源管理网上智能考勤系统源程序+mysql+系统+lw文档+远程调试
  5. Unity2018版本报错问题解决方法
  6. jsplumb php,jsplumb 中文教程 连线绘图工具库介绍 附简单在线demo与实战项目
  7. Xcode - VALID_ARCHS
  8. onchange比ajax触发快,Ajax后onchange
  9. 大三了,意识到了数学、物理、外语的重要……
  10. jfinal-utils