垃圾回收器为什么必须要停顿下?

简介: 垃圾回收器为什么必须要停顿下?

美丽又短暂的假期居然这么快就结束了,学习的小车轮继续的滚起来吧

垃圾回收器为什么必须要停顿下?

在垃圾收集器在获取根节点这一步时必须暂停用户线程的也就是我们常说的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)来解决问题了。

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

安全区域内发生了什么?

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

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

结尾

看完这些,你能回答下面的问题吗!

垃圾收集器为什么必须要停顿下?

安全点和安全区域的区别?

往期推荐

每日一个知识点系列:volatile的可见性原理

(最新 9000字) Spring Boot 配置特性解析

何时用多线程?多线程需要加锁吗?线程数多少最合理?

Spring Boot 知识清单(一)SpringApplication

高并发系统,你需要知道的指标(RT...)

相关文章
|
1月前
|
算法 Java
如何减少垃圾回收停顿时间,以提高高性能应用程序的响应性
如何减少垃圾回收停顿时间,以提高高性能应用程序的响应性
|
10月前
|
缓存 算法 Java
透彻理解JVM中垃圾回收GC生产参数,停顿时间+执行效率相关参数
停顿时间相关参数 部分垃圾回收器实现了GC执行时应用最大停顿时间的功能,所以提供参数用于应用控制停顿时间。另外,GC为了满足停顿时间,会设计和实现一些动态算法来调整堆空间,从而满足停顿时间这个目标。本节介绍相关参数。 该参数表示GC的最大的停顿时间。不同GC对于该参数的行为不一致,具体来说: 1)若Parallel GC中GC执行的时间超过该值,将导致调整新生代和老生代的大小(参数UseAdaptiveSizePolicy设置为true)。参数的默认值为4294 967 295,大约为50天(所以通常不会触发这个调整策略)。 2)若G1中GC执行的时间超过该值,将导致调整新生代的大小和
|
1月前
|
算法 Java
JVM GC和常见垃圾回收算法
JVM GC和常见垃圾回收算法
61 0
|
1月前
|
Java Go
Golang底层原理剖析之垃圾回收GC(二)
Golang底层原理剖析之垃圾回收GC(二)
61 0
|
1月前
|
存储 缓存 算法
JVM(四):GC垃圾回收算法
JVM(四):GC垃圾回收算法
|
1月前
|
存储 监控 算法
垃圾回收器、垃圾回收算法、空间分配担保、JVM调优、GC回收对象的过程
垃圾回收器、垃圾回收算法、空间分配担保、JVM调优、GC回收对象的过程
|
2天前
|
监控 算法 Java
JVM之GC算法的实现(垃圾回收器)
JVM之GC算法的实现(垃圾回收器)
|
4天前
|
算法 Java
垃圾回收机制(Garbage Collection,GC)是Java语言的一个重要特性,它自动管理程序运行过程中不再使用的内存空间。
【6月更文挑战第24天】Java的GC自动回收不再使用的内存,关注堆中的对象。通过标记-清除、复制、压缩和分代等算法识别无用对象。GC分为Minor、Major和Full类型,针对年轻代、老年代或整个堆进行回收。性能优化涉及算法选择和参数调整。
15 3
|
10天前
|
算法 Java
Java垃圾回收(Garbage Collection,GC)是Java虚拟机(JVM)的一种自动内存管理机制,用于在运行时自动回收不再使用的对象所占的内存空间
【6月更文挑战第18天】Java的GC自动回收内存,包括标记清除(产生碎片)、复制(效率低)、标记整理(兼顾连续性与效率)和分代收集(区分新生代和老年代,用不同算法优化)等策略。现代JVM通常采用分代收集,以平衡性能和内存利用率。
36 3
|
14天前
|
存储 监控 算法
深入理解Java的垃圾回收机制(GC)实现原理
深入理解Java的垃圾回收机制(GC)实现原理
21 1