引用计数算法的缺陷
代码:
/**
* -XX:+PrintGC 输出简要GC日志
* -XX:+PrintGCDetails 输出详细GC日志
* -Xloggc:gc.log 输出GC日志到文件
* -XX:+PrintGCTimeStamps 输出GC的时间戳(以JVM启动到当期的总时长的时间戳形式)
* -XX:+PrintGCDateStamps 输出GC的时间戳(以日期的形式,如 2013-05-04T21:53:59.234+0800)
* -XX:+PrintHeapAtGC 在进行GC的前后打印出堆的信息
* -verbose:gc
* -XX:+PrintReferenceGC 打印年轻代各个引用的数量以及时长
* <p>
* testGC()方法执行后,objA和objB会不会被GC呢?
* <p>
* VM Args:-XX:+PrintGCDetails -Xloggc:gc.log -XX:+PrintGCTimeStamps -XX:+PrintReferenceGC
*
*/
public class ReferenceCountingGC {
public Object instance = null;
private static final int _1MB = 1024 * 1024;
public static void main(String[] args) {
testGC();
}
/**
* 这个成员属性的唯一意义就是占点内存,以便在能在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();
}
}
结果:
1.596: [GC (System.gc()) 1.600: [SoftReference, 0 refs, 0.0001201 secs]1.600: [WeakReference, 11 refs, 0.0000754 secs]1.600: [FinalReference, 68 refs, 0.0001728 secs]1.600: [PhantomReference, 0 refs, 0 refs, 0.0000429 secs]1.600: [JNI Weak Reference, 0.0001345 secs][PSYoungGen: 6975K->719K(33280K)] 6975K->727K(110080K), 0.0045623 secs] [Times: user=0.00 sys=0.00, real=0.00 secs] 1.601: [Full GC (System.gc()) 1.603: [SoftReference, 0 refs, 0.0001014 secs]1.603: [WeakReference, 3 refs, 0.0000414 secs]1.603: [FinalReference, 0 refs, 0.0000400 secs]1.603: [PhantomReference, 0 refs, 0 refs, 0.0000403 secs]1.603: [JNI Weak Reference, 0.0000882 secs][PSYoungGen: 719K->0K(33280K)] [ParOldGen: 8K->666K(76800K)] 727K->666K(110080K), [Metaspace: 3037K->3037K(1056768K)], 0.0391800 secs] [Times: user=0.02 sys=0.00, real=0.04 secs]
ygc:
6975K->719K 表示年轻代占用从6975K降到719K
33280K 表示年轻代的大小
6975K->727K 表示整个堆占用从6975K降为727K
110080K 表示整个堆的大小
0.0045623 secs 表示这次GC总计所用的时间
full gc:
[PSYoungGen: 719K->0K(33280K)] [ParOldGen: 8K->666K(76800K)]
表示年轻代占用从719K降到0K,老年代从8K升到666K
727K->666K(110080K)
表示整个堆占用从727K降为666K
结论:两个对象互相引用也会被回收