在 JVM 中,有两个非常重要的知识点,一个是 JVM 的内存布局(JVM 运行时的数据区域),另一个便是废物收回。而废物收回中又有两个重要的知识点,一个是怎么确认 JVM 中的废物目标,另一个是运用不同的废物收集器进行废物收回。而本篇要讨论的是前者,后面的内容我们下一篇再聊。
废物目标的判定有两种常用的算法:引证计数器算法和可达性剖析算法。
1.引证计数器算法
引证计数算法(Reference Counting) 归于废物收集器的早期完成算法了,它指的是在创立目标时关联一个与之相对应的计数器,当此目标被运用时加 1,相反毁掉时 -1。当此计数器为 0 时,则表示此目标未运用,能够被废物收集器收回。
引证计数算法的优缺陷很明显,其优点是废物收回比较及时,实时性比较高,只要目标计数器为 0,则能够直接进行收回操作;而缺陷是无法处理循环引证的问题,比如以下代码:
public class RefCounterTest {
// 目标 A
static class RefObjectA {
private RefObjectB refObjectB;
public void setRefObjectB(RefObjectB refObjectB) {
this.refObjectB = refObjectB;
}
}
// 目标 B
static class RefObjectB {
private RefObjectA refObjectA;
public void setRefObjectA(RefObjectA refObjectA) {
this.refObjectA = refObjectA;
}
}
// 测验代码
public static void main(String[] args) {
RefObjectA objectA = new RefObjectA();
RefObjectB objectB = new RefObjectB();
objectA.setRefObjectB(objectB);
objectB.setRefObjectA(objectA);
objectA = null;
objectB = null;
}
}
如以上代码所示,即使是将 main 办法中的 objectA 和 objectB 都设置为 null,也便是这两个目标都彻底不运用了,但是由于二者存在相互引证的联系,所以它们所对应的目标计数器不为 0,这样循环引证导致废物数据无法被清除的事件就产生了。
2.可达性剖析算法
可达性剖析算法(Reachability Analysis) 是现在干流虚拟机中,运用最广泛的判断废物目标的完成算法,它指的是从目标的起点(GC Roots)开端向下查找,假如目标到 GC Roots 没有任何引证链相连时,也便是说此目标到 GC Roots 不可达时,则表示此目标能够被废物收回器所收回,如下图所示: 在 Java 语言中,可作为根节点(GC Roots)的目标有以下 4 类:
- Java 虚拟机栈中的引证目标,也便是 Java 虚拟机栈帧中,本地变量表所存储的(引证)目标。在 Java 虚拟机栈帧中存储的目标都是将来执行时,要运用的目标,所以和引证目标相关的目标都不能被收回;
- 本地办法栈中的引证目标和 Java 虚拟机栈中的引证目标相似,也不能被收回;
- 办法区中类静态属性引证的目标也能够作为 GC Roots;
- 办法区中常量引证的目标也能够作为 GC Roots。由于常量是保存在常量池中的,归于全局可运用的目标,所以也能作为 GC Roots。
3.有关“引证”
不管是引证计数法还是可达性剖析算法都与目标的“引证”有关,这说明目标的引证决定了目标的存亡,而 Java 中的引证也比较复杂,它从 JDK 1.2 之后,(引证)分成了以下 4 种类型:
-
强引证:在代码中普遍存在的,相似
Object obj = new Object()
这类引证,只要强引证还在,废物收集器永远不会收回掉被引证的目标; - 软引证:是一种相对强引证弱化一些的引证,能够让目标豁免一些废物收集,只要当 JVM 认为内存不足时,才会去企图收回软引证指向的目标,JVM 会确保在抛出 OutOfMemoryError 之前,清理软引证指向的目标;
- 弱引证:非必需目标,但它的强度比软引证更弱,被弱引证关联的目标只能生存到下一次废物收集产生之前;
- 虚引证:也称为幽灵引证或幻影引证,是最弱的一种引证联系,无法通过虚引证来获取一个目标实例,为目标设置虚引证的目的只要一个,便是当着个目标被收集器收回时收到一条体系通知。
总结
废物目标的判定有两种常用的算法:引证计数器算法和可达性剖析算法。其中引证计数器算法完成简单、运行高效,但是存在循环引证的问题,所以干流的虚拟机运用的都是可达性剖析算法,可达性剖析算法是从目标的根节点 GC Roots 向下查找,假如根节点相连便是正常的目标,否则为废物目标能够被废物收回器收回。
本文已收录到 Gitee 开源仓库《Java 面试攻略》,其中包含的内容有:Redis、JVM、并发、并发、MySQL、Spring、Spring MVC、Spring Boot、Spring Cloud、MyBatis、设计模式、消息行列等模块。Java 面试有它就够了:超全 Java 常见面试题,继续更新…