JVM-Java 中使用的标记阶段的算法: 可达性分析算法中 GC Roots 有哪些004

1,017 阅读3分钟

上一篇:003-JVM - 标记阶段的算法:怎么确定垃圾 juejin.cn/post/690816…

gc roots 有哪些呢?这个是面试题,也要背下来,如果不想进大厂的话,可以不背。

  1. 常规 gc roots

1、JVM stack
虚拟机栈中引用的对象
比如: 各个线程被调用的方法中使用到的参数、局部变量等
2、nativ method stack
JNI( 通常说的本地方法) 引用的对象
3、runtime constant pool
运行时常量池
4、static references in method area
(堆 jdk8)中类静态属性引用的对象
比如: Java 类的引用类型静态变量
(堆 jdk8) 中常量引用的对象
比如: 字符串常量池 (String Table ) 里的引用
5、Clazz
Java 虚拟机内部的引用。
基本数据类型对应的 Class 对象, 一些常驻的异常对象( 如:NullPointerException 、OutOfMemoryError) , 系统类加载器
6、所有被同步锁 synchronized 持有的对象

除了这些固定的 GC Roots 集合以外, 根据用户所选用的垃圾收集器以及当前回收的内存区域不同, 还可以有其他对象 “临时性” 地加入, 共同构成完整 GC Roots 集合。比如: 分代收集和局部回收( Partial GC)
如果只针对 Java 堆中的某一块区域进行垃圾回收( 比如: 典型的只针对新生代) , 必须考虑到内存区域是虚拟机自己的实现细节, 更不是孤立封闭的, 这个区域的对象完全有可能被其他区域的对象所引用,这时候就需要一并将关联的区域对象也加入 GC Roots 集合中去考虑, 才能保证可达性分析的准确性。
局部回收:意思如果分代回收的时候,比如对年轻代进行回收,那么在老年代中的变量 (其指向了年轻代。),也需要放入 Roots Set 中。否则就会出现误伤!
小技巧:由于 Root 采用栈方式存放变量和指针, 所以如果一个指针, 它保存了堆内存里面的对象, 但是自己又不存放在堆内存里面, 那它就是一个 Root。

  1. 临时 gc roots 除了这些固定的 GC Roots 集合以外, 根据用户所选用的垃圾收集器以及当前回收的内存区域不同, 还可以有其他对象 “临时性” 地加入, 共同构成完整 GC Roots 集合。比如: 分代收集和局部回收( Partial GC)

如果只针对 Java 堆中的某一块区域进行垃圾回收( 比如: 典型的只针对新生代) , 必须考虑到内存区域是虚拟机自己的实现细节, 更不是孤立封闭的, 这个区域的对象完全有可能被其他区域的对象所引用,这时候就需要一并将关联的区域对象也加入GC Roots集合中去考虑, 才能保证可达性分析的准确性。 局部回收:意思如果分代回收的时候,比如对年轻代进行回收,那么在老年代中的变量(其指向了年轻代。),也需要放入 Roots Set 中。否则就会出现误伤! 小技巧:由于 Root 采用栈方式存放变量和指针, 所以如果一个指针, 它保存了堆内存里面的对象, 但是自己又不存放在堆内存里面, 那它就是一个 Root。(此说法不严谨:比如上面提到的 “临时性” 地加入的;jdk8 中的 StringTable、Static 变量等,均在堆中。 但是可以作为一般的评判标准)

  1. 总结 常规的 6 中需要在 roots set 中 特殊的两种在 roots set 中。

全文完 本文由 简悦 SimpRead 优化,用以提升阅读体验 使用了 全新的简悦词法分析引擎 beta,点击查看详细说明

  1. 常规 gc roots
  2. 临时 gc roots
  3. 总结