大家都知道JVM有垃圾回收机制,JVM会自动回收死去的对象。那么我们如何才能知道对象是否死亡(不再被任何途径使用的对象)呢?
很多书上写到用引用计数算法。
引用计数算法
给对象添加一个引用计数器,每当有一个地方使用它时,计数器就会加1;当引用失效时,计数器减1;任何时刻计数器为0的对象就是不能再被使用的。
这种方式无法解决的一个问题是对象之间的相互循环引用。 比如对象A和对象B都有字段instance , A.instance=B 及 B.instance=A,除此之外,两个对象再无其他引用。实际上这两个对象已经不可能被访问了,但是使用引用计数算法,他们的引用计数器不为0,但是GC确会回收它们。
既然这个不行,那么引出下一个方法 可达性分析算法
可达性分析算法
通过可达性分析来判断对象是否存活。这个算法的基本思想是通过一系列的成为“GC Roots”的对象作为起始点,从这些节点开始向下搜索,搜索所走过的路径成为引用链,当一个对象没有任何引用链相连时,则证明此对象不可用
绿色为可用对象,红色为不可用对象。
GC Roots分为下面几种
1 虚拟机栈(栈帧的本地变量表)中引用对象
2 方法区中类静态属性引用对象
3 方法区中常量引用对象
4 本地方法栈(Native)引用对象
无论上面使用引用计数算法还是使用可达性分析算法判断对象的引用是否可达,判断对象的存活都与引用相关。接下来看一下关于引用强度的分类
强引用
代码中普遍存在的 类似 Object o = new Object(); 只要强引用还存在就不会被垃圾回收器回收
软引用
描述一些还有用但是非必须的对象。在系统发生内存溢出之前,会将软引用对象列为二次回收对象,如果回收完成内存还是不足才会抛出内存溢出异常。
弱引用
描述非必需的对象。强度比软引用弱,被弱引用关联的对象只能存活到下一次垃圾收集发生之前
虚引用
最弱的一种关系引用。是否有虚引用完全不会影响对象的生存时间。
其实我们就算在可达性分析算法中不可达对象,也并不是马上会死亡。暂时处于一种判处死刑的状态。要真正宣告死亡必须经历两次标记过程。类似与人类的先由法院判决死刑,然后再执行枪决才会死亡一样。
如果对象通过可达性分析后发现没有与GC Roots相连接的引用链,那么它将被进行第一次标记并且进行一次筛选,筛选的条件是此对象是否有必要执行finalize()方法,当对象没有覆盖finalize()方法,或者finalize()方法已经被虚拟机调用过,那么这个对象将会被垃圾回收,宣告死亡。
任何一个对象的finalize()方法都只会被系统调用一次。