Java基础、中级、高级、架构面试资料

面试官:JVM垃圾回收器为什么必须要停顿下?

JAVA herman 2509浏览
公告:“业余草”微信公众号提供免费CSDN下载服务(只下Java资源),关注业余草微信公众号,添加作者微信:xttblog2,发送下载链接帮助你免费下载!
本博客日IP超过2000,PV 3000 左右,急需赞助商。
极客时间所有课程通过我的二维码购买后返现24元微信红包,请加博主新的微信号:xttblog2,之前的微信号好友位已满,备注:返现
受密码保护的文章请关注“业余草”公众号,回复关键字“0”获得密码
所有面试题(java、前端、数据库、springboot等)一网打尽,请关注文末小程序
视频教程免费领
腾讯云】1核2G5M轻量应用服务器50元首年,高性价比,助您轻松上云

面试高级工程师,或者薪资 15K 以上时,你很可能会遇到被面试官问到各种各样的 JVM 知识点。最近我在面试候选人的时候,问到“JVM垃圾回收器为什么必须要停顿下?”几乎没人能回答出来。所以,今天我们就一起来写篇文章,聊一聊这个知识点。

在垃圾收集器在获取根节点这一步时必须暂停用户线程的也就是我们常说的 STW,目前可达性分析算法耗时最长的查找引用链的过程已经可以做到和用户线程一起并发,但根节点枚举的获取还必须是要在一个能保证一致性的快照中才能进行。

这里说的一致性就是根节点枚举分析期间执行子系统看起来就像被冻结在某个时间点上,不会出现一边分析,根节点的对象引用关系还在不断的变化的情况。这也是导致垃圾收集过程必须停顿所有用户线程的其中一个重要原因,即便是号称停顿时间可控的 CMS、G1、ZGC 等,跟节点分析时也是必须要停顿的。

GC Roots

都知道JVM内对象存活判定一般用可达性分析算法,也就是说在HotSpot 使用里面维护了很多根节点(GC Roots)。

GC Roots种类:

  • 静态变量引用的对象
  • 常量引用的对象
  • 栈针本地变量表引用的对象
  • JNDI 引用的对象

什么是 OopMap?

目前主流JVM垃圾收集,在当用户线程停顿下后其实是不需要一个不漏的检查完所有的执行上下文和全局引用位置的。在HotSpot中是使用一组成为OopMap的数据结构来达到这个目的的。

当类加载动作完成时,HotSpot就会将对象内的类型、偏移量等数据计算出来,这时在垃圾收集器扫描的时候就可以直接得到这些信息了,并不需要一个不漏的从GC Roots开始查找。

借助于OopMap,虚拟机可以快速枚举GC Root引用,这就是典型的以空间换时间。但导致引用关系变化非常多,又不能生成过多的OopMap从而导致存储资源的浪费,所以又出现了安全点和安全区域。

什么是安全点?

在OopMap的帮助下,可以快速的完成GC Roots数据扫描,但可以导致引用关系变化的可能太多了,也就是说导致OopMap内容变化的指令非常多,不可能每次变化都生成对应的OopMap。

所以,在某个特定的位置来记录关系信息到OopMap,这些位置就被称为安全点。其实也就是在代码执行到达指定的位置才能够暂停进行信息收集。

举例Serial 收集器(其他收集器也差不多):

  • 单线程收集器,收集的时候会暂停所有用户线程(简称STW)
  • 客户端模式下默认收集器
  • 简单高效,是所有收集器中额外内存消耗最小的

安全点的选定:

具有让程序长时间执行的特征,例如方法调用、循环跳转、异常跳转等。

怎么到达安全点?

在实际情况下,是不可能在发生垃圾收集的时候所有的线程都正好在安全点,所以就需要线程都跑到最近的安全点然后停顿下来。

有两种方案:

抢先试中断(Preemptive Suspension):(现在几乎没有用这种的了)

不需要线程的执行代码主动配合,在垃圾收集发生时,系统首先把所有用户线程全部中断,如果发现有用户线程中断的地方不再安全点上,就恢复这条线程执行,让它一会再重新中断,直到到达安全点。

主动式中断(Voluntary Suspension):

在垃圾收集需要中断线程的时候,不直接对线程操作,仅简单的设置一个标志位,各个线程执行过程时会不停的主动去轮询这个标志,一旦发现中断标志为true时就在自己最近的安全点上主动挂起。

什么是安全区域?

安全点似乎解决了让虚拟机内部线程主动停顿,整个虚拟机进入垃圾回收状态的问题。但在实际情况下,如果线程处于sleep 或Blocked状态的话是没有分配CPU时间的,这时线程是无法响应虚拟机的中断请求,不能再走到安全点进行挂起,而虚拟机也不能持续的等待线程被重新激活分配CPU。这种情况,就必须引入安全区域(Safe Region)来解决问题了。

安全区域,可以看作是安全点的扩展。指的是能够确保在某一段代码片段中,引用关系不会发生变化,在这个区域中任意地方开始来及手机都是安全的。

安全区域内发生了什么?

当线程执行到安全区域里的代码时,会先标识自己进入了安全区域,如果这时段里进行了垃圾收集虚拟机就不必去管这些已经标识过的线程了

当线程离开安全区域时,它要检查下虚拟机是否完成了根节点的扫描或者垃圾收集过程中需要停顿的阶段。如果完成了,那线程就会继续执行。否则就必须一直等待,直到收到可以离开安全区域的信号。

业余草公众号

最后,欢迎关注我的个人微信公众号:业余草(yyucao)!可加作者微信号:xttblog2。备注:“1”,添加博主微信拉你进微信群。备注错误不会同意好友申请。再次感谢您的关注!后续有精彩内容会第一时间发给您!原创文章投稿请发送至532009913@qq.com邮箱。商务合作也可添加作者微信进行联系!

本文原文出处:业余草: » 面试官:JVM垃圾回收器为什么必须要停顿下?