题目
如何判断对象为垃圾(如何判断对象是否可回收)、哪些对象的引用可以作为 GC Roots
答案
@[toc] --- 判断对象是否可回收的两种方法: - 引用分析法 - 可达性分析法(目前主流的 JVM 用的都是可达性分析算法) ## 引用分析法 所谓引用计数法就是在对象中添加一个字段作为引用计数器,每当有一个地方引用这个对象时,计数器的值就加一;当引用失效时,计数器值就减一;计数器为零的对象就是可以被回收的对象。 目前主流的 JVM 里面都没有选用引用计数算法来管理内存。主要原因是,这个看似简单的算法需要考虑很多例外情况,比如,**单纯的引用计数就很难解决对象之间相互【循环引用】的问题**。 所谓对象之间的相互循环引用,举个简单的例子,如下代码:对象 objA 和objB 都有字段 instance,赋值令 `objA.instance=objB` 及 `objB.instance=objA`,除此之外,这两个对象再无任何引用 ![](https://cs-wiki.oss-cn-shanghai.aliyuncs.com/img/20220227204354.png) 当我们令 objA 和 objB 为 null 的时候,意思就是不想再让他俩指向的对象被其他人访问了,虚拟机可以回收掉了,但是它们因为互相引用着对方,导致它们的引用计数都不为零,所以引用计数算法也就无法回收它们 ![](https://cs-wiki.oss-cn-shanghai.aliyuncs.com/img/20220227204809.png) ## 可达性分析法 这个算法的基本思路可以理解为一棵**多叉树**:就是通过一系列称为 “**GC Roots**” 的根节点作为**起始节点集**,从这些节点开始,根据引用关系向下搜索,如果从 GC Roots 到某个对象不可达时,则说明此对象是可以被回收的。 所以,可达性分析可以分成两个阶段 - **根节点枚举** - **从根节点开始遍历对象图** ### 哪些对象的引用可以作为 GC Roots? A garbage collection root is an object that is accessible from outside the heap. (**GC roots 是可以从堆外部访问到的对象**): - 在**虚拟机栈 / 本地方法栈**中引用的对象 - 在方法区中**类的静态变量(static)或者 常量 (final)** 引用的对象(JDK 1.7 开始静态变量和字符串常量池从方法区移动到了堆中) - **JVM 内部的引用**,如基本数据类型对应的 Class 对象,一些常驻的异常对象(比如 NullPointExcepiton、OutOfMemoryError)等,还有系统类加载器等。这个很好理解,毕竟如果这些核心的系统类对象被回收了,程序就没办法运行了 - 所有被**同步锁**(synchronized 关键字)持有的对象 - ...... > 简单来说,GC 管理的主要区域是 Java 堆,一般情况下只针对堆进行垃圾回收。方法区、虚拟机栈和本地方法栈等不被 GC 所管理,因而选择这些区域内的对象作为 GC roots,被 GC roots 引用的对象不被 GC 回收。