小知识,大挑战!本文正在参与“程序员必备小知识”创作活动。
垃圾收集器在进行垃圾回收前需要确定哪些对象是存活的,目前主流有两种算法:引用计数法和可达性分析法。
引用计数法
为每一个对象添加一个引用技术器,每有一处引用时计数器的值加一,当引用失效时计数器的值减一,当计数器为0则表示对象不会再被使用。引用计数法在主流的Java虚拟机中没有选用,主要是由于难以解决对象之间循环引用的问题。 以下面代码为例,对象objA和objB进行了循环引用,导致它们的引用技术都不为零,引用计数法无法回收它们。
public class ReferenceCountingGC {
public Object instance = null;
private static final int _1MB = 1024 * 1024;
/**
* 这个成员属性的唯一意义就是占点内存,以便能在GC日志中看清楚是否有回收过
*/
private byte[] bigSize = new byte[2 * _1MB];
public static void testGC() {
ReferenceCountingGC objA = new ReferenceCountingGC();
ReferenceCountingGC objB = new ReferenceCountingGC();
objA.instance = objB;
objB.instance = objA;
objA = null;
objB = null;
// 假设在这行发生GC,objA和objB不能被回收
System.gc();
}
}
可达性分析法
主流的程序语言采用的对象存活算法主要是可达性分析算法,基本思路是以GC Roots作为起始节点根据引用关系向下搜索,将路径形成一条引用链,不在链上的对象均为可回收对象。
可以被作为GC Roots的对象有一下几种
- 虚拟机栈中引用的对象,主要是栈帧中的本地变量表,这里存有方法的参数、局部变量等。
- 在本地方法栈中引用的对象。
- 方法区中类静态属性引用的对象,主要是Java类的引用类型静态变量。
- 方法区中常量引用对象,主要是对于字符串常量池的引用。
- 被同步锁synchronized持有的对象。
- 虚拟机内部的引用,例如基本数据类型对应的Class对象(Integer、Charactor等)、异常对象(NullPointException、OutOfMemoryError)、系统类加载器。
- 反映虚拟机内部情况的JMXBean、本地代码缓存等。