简介
本文介绍可作为GC Roots的对象有哪些。
对象是否要回收?
判断对象是否要回收有两种方法:引用计数算法、可达性分析算法。JVM是通过可达性分析算法来判断的。
引用计数算法
给对象中添加一个引用计数器。每当有一个地方引用它时,计数器值就加1;当引用失效时,计数器值减1;任何时刻计数器为0的对象就是没有被使用的(需要被回收)。
缺点:无法解决循环引用问题:两个对象互相引用,引用计数始终不为 0,导致无法被回收,而实际上应该需要被回收。
可达性分析算法
在主流的商用程序语言(Java、C#、Lisp)的主流实现中,都是称通过可达性分析(Reachability Analysis)来判定对象是否存活的。
将所有称为“GC Roots”的对象作为起点,从这些节点开始向下搜索,搜索所走过的路径称为引用链(Reference Chain)。当一个对象到GC Roots没有任何引用链相连(用图论的话来说,就是从GC Roots到这个对象不可达)时,则说明此对象是没有被使用的(需要被回收)。如下图所示,对象object5、object6、object7虽然互相有关联,但是它们到GC Roots是不可达的,所以它们将会被判定为是可回收的对象。
可作为GC Roots的对象
Java对象并不是只有用户才能new,虚拟机内部也new了一些。只要从这个顶部对象出发能发现存活对象,它们就是GC Roots。
用户的GC Roots对象
- 栈中的对象
- 虚拟机栈(栈帧中的本地变量表)中引用的对象。
- static修饰的对象
- 方法区中类静态属性引用的对象。
- static final修饰的对象
- 方法区中常量引用的对象。
- Native方法引用的对象
- 本地方法栈中JNI引用的对象。
GC Roots大全
类型 | 说明 |
System Class | 由引导程序/系统类加载器加载的类型。例如,rt.jar中的所有内容(如java.util.*)。 |
JNI Local | 本机原生代码中的局部变量,例如用户定义的JNI代码或JVM内部代码。 |
JNI Global | 本机原生代码中的全局变量,例如用户定义的JNI代码或JVM内部代码。 |
Thread Block | 从当前活动的线程块引用的对象。 |
Thread | 已经启动运行的线程 thread。 |
Busy Monitor | 忙碌的监视器代码,调用了wait()或notify()或被synchronized同步的。 |
Java Local | 局部变量。例如,输入参数或仍在线程堆栈中的方法的局部创建对象。 |
Native Stack | 本机原生代码中的输入或输出参数,例如用户定义的JNI代码或JVM内部代码。 |
Finalizable | 可终结对象,队列中等待其终结器运行的对象。 |
Unfinalized | 未终结对象,具有finalize方法但尚未完成且尚未在终结器队列中的对象。 |
Unreachable | 不可达对象,无法从任何其他根访问的对象,MAT使用。 |
Java Stack Frame | Java栈框架,持有局部变量。解析Dump时使用。 |
Unknown | 根类型未知对象。MAT分析Dump文件时的特殊类型,归类不可知类型。 |
请先
!