接上一篇《JVM便秘攻略一》
4 对象已死吗?
堆里存放着Java世界中几乎所有的对象实例,垃圾收集器在对堆进行回收前,要确定哪些对象还活着,哪些已经死了。
4.1 引用计数算法
给对象加一个引用计数器,每当有一个地方引用它时,计数器值就+1,;
当引用失效时,计数器值就-1;
任何时候计数器为0的对象就是不可能被使用的。
例子
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 obj1 = new ReferenceCountingGC();
ReferenceCountingGC obj2 = new ReferenceCountingGC();
//相互引用,计数器各为1
obj1.instance = obj2;
obj2.instance = obj1;
obj1 = null;
obj2 = null;
//结果是JVM并没有因为它们互相引用就不回收了
//所以JVM不是通过引用计数算法来判断对象是否存活
System.gc();
}
public static void main(String[] args) {
testGC();
}
}
-XX:+PrintGC 输出GC日志
-XX:+PrintHeapAtGC 在进行GC的前后打印出堆的信息
-XX:+PrintGCDetails 输出GC的详细日志
-XX:+PrintGCTimeStamps 输出GC的时间戳(以基准时间的形式)
-XX:+PrintGCDateStamps 输出GC的时间戳(以日期的形式,2013-05-04T21:53:59.234+0800)
-Xloggc:../logs/gc.log 日志文件的输出路径
使用eclipse控制台打印GC日志,
控制台输出日志:
[GC (System.gc()) [PSYoungGen: 6092K->616K(38400K)] 6092K->624K(125952K), 0.0011515 secs(回收时间)]
[Full GC (System.gc()) [PSYoungGen: 616K->0K(38400K)] [ParOldGen: 8K->510K(87552K)] 624K->510K(125952K), [Metaspace: 2542K->2542K(1056768K)], 0.0049943 secs]
GC日志说明:
GC打印时间: [垃圾回收类型回收时间: [收集器名称: 年轻代回收前占用大小->年轻代回收后占用大小(年轻代当前容量),
年轻代局部GC时JVM暂停处理的时间] 堆空间GC前占用的空间->堆空间GC后占用的空间(堆空间当前容量)
,GC过程中JVM暂停处理的时间]。
垃圾回收类型:分为GC和Full GC.
GC一般为堆空间某个区发生了垃圾回收,
Full GC基本都是整个堆空间及持久代发生了垃圾回收
PSYoungGen:年轻代(新生代)发生了GC
ParOldGen:老年代发生了GC
PSYoungGen: 6092K(年轻代垃圾回收前的大小)->616K(年轻代垃圾回收以后的大小)(38400K)(年轻代的总大小)
由此可知,JVM并没有因为两个对象相互引用就不回收它们,也从侧面说明JVM不是通过引用计数算法来判断对象是否活着。
4.2 可达性分析算法(根搜索算法)
在Java语言中,可作为GC Roots的对象包括下面几种:
4.3 引用
4.3.1 强引用(Strong Reference)
4.3.2 软引用
4.3.3 弱引用
4.3.4 虚引用
本文学习自
《深入理解java虚拟机》
学堂在线-清华大学-许斌《JAVA程序设计进阶》