判断对象是否存活的算法一般是这样的:给对象中添加一个引用计数器,每当有一个地方引用它时,计数器就加1,当引用失效时,计数器就减1;任何时刻计数器为0的对象就是不可能在被使用的。
客观的说,引用计数算法的实现简单,判定的效率很高,在大部分的情况下是一个不错的算法,也要一些著名的应用实例,比如微软公司的COM技术,使用ActionScript 3 的FlashPlayer,Python语言和在游戏脚本领域被广泛应用的Squirrel中都使用了引用计数算法进行内存管理。但是,至少主流的Java虚拟机里面没有选择引用计数算法来管理内存,其中主要的原因是它很难解决对象之间的相互循环引用的问题。
下面看一下示意图方便理解:
左侧为堆,右边为栈。当堆中的对象之间有相互引用,但是栈中的应用并未指向相应对象的时候,使用引用计数器算法会存在弊端,上面也提及到了。就是对象实际上已经没有用了,但是由于对象之间存在相互的引用,对象的引用计数器不为0,所以该算法不会收集垃圾对象所占用的内存。
下面看一下代码验证当前JDK中的内存回收算法是不是引用计数器算法。在代码之前我们想要看到垃圾回收器的信息,要配置打印垃圾收集日志。这里有两个参数:
- -verbose:gc : 打印垃圾回收的简单信息
- -xx:+PrintGCDetails :详细信息
package jishuqisuanfa;
public class Main {
private Object instance;
public Main() {
byte [] m = new byte[20*1024*1024];
}
public static void main(String[] args) {
Main m1 = new Main();
Main m2 = new Main();
m1.instance = m2;
m2.instance = m1;
m1 = null;
m2 = null;
System.gc();
}
}
结果:
这里红框中显示对象的内存被回收了,显然,我们的JDK中并没有采用这种算法来收集垃圾对象所占的内存。