深入浅出JVM(十六)之三色标记法与并发可达性分析

简介: 深入浅出JVM(十六)之三色标记法与并发可达性分析

上篇文章深入浅出JVM(十五)之垃圾回收器(上篇)介绍性能指标吞吐量和延迟、串行收集器、并行收集器以及吞吐量优先收集器

为了更好的描述并发垃圾收集器,本篇文章将先深入浅出的介绍三色标记法以及并发可达性分析遇到的问题以及解决方案

三色标记法

JVM中使用可达性分析算法来判断对象是否继续使用

当对象不可达时,执行过finalize方法或者finalize方法搭不上引用链时才能回收这些对象

不理解如何判断对象不再使用的同学可以看这篇文章深入浅出JVM(十一)之如何判断对象“已死”

为了更好的说明并发可达性分析,我们使用三色标记法模拟,先说明三色标记法

三色标记法的颜色、流程说明

三色标记法的三种颜色说明

黑色:当前对象被扫描过,并且它引用的对象也被扫描

灰色:当前对象被扫描过,至少有一个引用未被扫描

白色:当前对象未被扫描过

GC 根节点总是黑色的,因为它们隐式可达

扫描时,从GC Roots节点(灰色)开始,将它引用的对象全染成灰色,再将自己染成黑色,再从灰色对象集合中遍历上述操作,类似树的层序遍历

当扫描完毕时,如果对象依旧是白色说明这个对象是不可达对象

比如图中的a变成黑色,说明a引用的对象b已经被扫描了;而b是灰色,说明b至少有一个引用的对象没被扫描(b引用的c就还未被扫描)

image.png

b将引用的c染成灰色后,将自己染成黑色,再从灰色对象集合中取出对象c进行后续操作

image.png

并发可达性分析

当GC、用户线程并发执行时,就会出现对象引用可能改变的情况,可能造成浮动垃圾和对象丢失的情况

浮动垃圾

一种情况会把原本死亡的对象改成活的对象,成为浮动垃圾,下次再回收掉

比如c将引用的d、e染成灰色后将自己染成黑色

image.png

因为还未扫描结束,用户线程将c引用e删除了c.e = null,本来e没有被引用应该变成垃圾

但由于并发执行,后续GC线程从灰色对象集合中获取d、e进行处理,最终会被染黑,e就变成浮动垃圾,本轮GC不会回收e

image.png

浮动垃圾的出现可以被接受,本轮不GC,下次GC也会进行回收

对象丢失

另一种情况会把原本存活的对象变成死亡的对象从而进行回收,十分危险

在从灰色对象拿出对象c 处理前,用户线程将c引用e删除c.e = null,后续c就不会将e染成灰色,只将d染成灰色

image.png

处理完对象c后,用户线程修改引用,让对象b引用对象eb.e = e,对象e变成需要使用的对象,但最终处理完d后,对象c依旧是白色

这种情况下就会发生对象丢失,对象c可能被GC回收,这种情况是危险的,不允许出现

image.png

经过研究表明对象消失需要满足的条件:

  1. 插入一条或多条从黑色对象到白色对象的新引用
  2. 删除全部从灰色对象到该白色对象的直接或间接引用

只需要破坏其中一条就可以避免对象消失

增量更新和原始快照分别破坏条件1、2

增量更新和原始快照会借助写屏障来处理,写屏障可以理解成AOP(在执行核心方法的前、后可以执行其他操作)

 //写前屏障处理
 //执行核心方法
 //写后屏障处理

增量更新

增量更新使用写后屏障,某个对象新增的引用时,将该对象记录下来,扫描完后将这个对象变为灰色对象重新扫描,在后续这个重新扫描的阶段需要用户线程STW

使用重新扫描,短暂STW的方式破坏条件一

用上面那张对象丢失的图举例的话,就是b对象在新增e引用时,后续会将b对象变为灰色重新扫描

image.png

重新扫描后,e对象最终也染黑

image.png

原始快照

原始快照使用写前屏障,在删除引用前保存要删除的引用,在扫描完毕后将这些删除的引用变为灰色对象重新扫描

原始快照破坏条件二,将白色对象变为灰色

并且GC开始后发生新增引用时,使用TAMS(Top at Mark Start)指针对新增引用进行记录(隐式可达)

对象c删除引用的对象e时记录对象e,扫描完毕时如下

image.png

STW重新扫描时,会将记录的对象e变灰色重新扫描,对象e变成了浮动垃圾;而新增的对象g用TAMS指针隐式可达直接变黑

image.png

由于被删除引用变灰,它可能变成浮动垃圾

总结

本篇文章围绕并发的可达性分析深入浅出的解析三色标记法、并发可达性分析可能出现的浮动垃圾,对象丢失问题以及解决对象丢失问题的增量更新、原始快照两种方式

在三色标记法中,黑色代表已经扫描完成、灰色代表至少有一个引用未扫描、白色代表还未扫描,GC根节点默认黑色隐式可达

三色标记法从GC根节点开始将引用对象变成灰色并放入灰色集合,并将自己变成黑色,接着再从灰色集合中取出下一个对象进行处理,直到灰色集合为空,还是白色的对象就是不可达对象

用户、GC线程并发执行时,可能改变对象的引用关系,可能造成浮动垃圾、对象消失的问题;浮动垃圾可以接受,下次GC会进行回收,但是对象消失是不能接受的

对象消失发生的两个条件是黑色对象新增到白色对象的引用和删除所有灰色对象到白色对象的间接/直接引用

增量更新使用写后屏障破坏条件一,记录新增白色对象引用的黑色对象,扫描完毕后STW将这个黑色对象变为灰色对象重新扫描

原始快照使用写前屏障破坏条件二,记录被删除的白色对象,使用TAMS指针让新增引用隐式可达,扫描完笔后STW将记录的白色对象变成灰色对象重新扫描,并且将隐式可达的对象变黑

最后

  • 参考资料
  • 《深入理解Java虚拟机》

本篇文章将被收入JVM专栏,觉得不错感兴趣的同学可以收藏专栏哟~

觉得菜菜写的不错,可以点赞、关注支持哟~

有什么问题可以在评论区交流喔~

相关文章
|
1月前
|
小程序 Oracle Java
JVM知识体系学习一:JVM了解基础、java编译后class文件的类结构详解,class分析工具 javap 和 jclasslib 的使用
这篇文章是关于JVM基础知识的介绍,包括JVM的跨平台和跨语言特性、Class文件格式的详细解析,以及如何使用javap和jclasslib工具来分析Class文件。
41 0
JVM知识体系学习一:JVM了解基础、java编译后class文件的类结构详解,class分析工具 javap 和 jclasslib 的使用
|
1月前
|
存储 算法 Java
【JVM】垃圾释放方式:标记-清除、复制算法、标记-整理、分代回收
【JVM】垃圾释放方式:标记-清除、复制算法、标记-整理、分代回收
49 2
|
1月前
|
存储 Java PHP
【JVM】垃圾回收机制(GC)之引用计数和可达性分析
【JVM】垃圾回收机制(GC)之引用计数和可达性分析
56 0
|
4月前
|
Java
jmap 查看jvm内存大小并进行dump文件内存分析
jmap 查看jvm内存大小并进行dump文件内存分析
92 3
|
4月前
|
运维 监控 Java
(十)JVM成神路之线上故障排查、性能监控工具分析及各线上问题排错实战
经过前述九章的JVM知识学习后,咱们对于JVM的整体知识体系已经有了全面的认知。但前面的章节中,更多的是停留在理论上进行阐述,而本章节中则更多的会分析JVM的实战操作。
107 1
|
3月前
|
监控 JavaScript Java
JVM源码级别分析G1发生FullGC元凶的是什么
线上系统遭遇频繁Old GC问题,监控显示出现多次“to-space exhausted”日志,这表明垃圾回收过程中因年轻代 Survivor 区或老年代空间不足导致对象晋升失败。通过 JVM 源码分析,此问题源于对象转移至老年代失败时,JVM 无法找到足够的空间存放存活对象。进一步排查发现大对象分配占用了预留空间,加剧了空间不足的情况。使用 JFR 分析工具定位到定期报表序列化导致大量大对象生成,通过改用堆外内存进行序列化输出,最终解决了频繁 Old GC 问题。
116 0
|
4月前
|
人工智能 Java
JVM内存问题之当老年代缓慢增加且Full GC无法清除时,应如何使用MAT进行分析
JVM内存问题之当老年代缓慢增加且Full GC无法清除时,应如何使用MAT进行分析
193 0
|
1月前
|
存储 安全 Java
jvm 锁的 膨胀过程?锁内存怎么变化的
【10月更文挑战第3天】在Java虚拟机(JVM)中,`synchronized`关键字用于实现同步,确保多个线程在访问共享资源时的一致性和线程安全。JVM对`synchronized`进行了优化,以适应不同的竞争场景,这种优化主要体现在锁的膨胀过程,即从偏向锁到轻量级锁,再到重量级锁的转变。下面我们将详细介绍这一过程以及锁在内存中的变化。
37 4
|
6天前
|
Arthas 监控 Java
JVM进阶调优系列(9)大厂面试官:内存溢出几种?能否现场演示一下?| 面试就那点事
本文介绍了JVM内存溢出(OOM)的四种类型:堆内存、栈内存、元数据区和直接内存溢出。每种类型通过示例代码演示了如何触发OOM,并分析了其原因。文章还提供了如何使用JVM命令工具(如jmap、jhat、GCeasy、Arthas等)分析和定位内存溢出问题的方法。最后,强调了合理设置JVM参数和及时回收内存的重要性。
|
4天前
|
Java Linux Windows
JVM内存
首先JVM内存限制于实际的最大物理内存,假设物理内存无限大的话,JVM内存的最大值跟操作系统有很大的关系。简单的说就32位处理器虽然可控内存空间有4GB,但是具体的操作系统会给一个限制,这个限制一般是2GB-3GB(一般来说Windows系统下为1.5G-2G,Linux系统下为2G-3G),而64bit以上的处理器就不会有限制。
7 1