上面我们讲了判断对象是否存活的算法有两种:引用计数算法与可达性分析算法。这两种算法均是回收那些垃圾对象的。
那么除了这两种算法判断对象是否是垃圾对象外,JVM还会有后续操作继续判断该对象是否“真正死亡”么?
这一章我们来聊聊JVM究竟还会经过哪些操作判断对象是真正死亡的。
在经过相关算法初步判断该对象是垃圾对象后,会将此对象处于“缓刑”阶段,也就是说,并不会让它马上死掉,还有逃生的机会。
在使用可达性分析算法判断该对象没有与GC Roots的连接的引用链后,会将此对象进行第一次标记,并进行筛选;筛选条件是:此对象是否有必要执行 finalize()方法。
在该对象并没有重写 finalize()方法或者 finalize()方法已经被虚拟机调用,都会被视为 没有必要再执行 finalize()方法。
如果该对象判断为 有必要执行finalize()方法,那么该对象将会放到一个叫做 F-Queue 的队列之中,并在稍后由一条虚拟机自动建立的、低优先级的Finalizer线程去执行(会触发这个方法,并不会等待到它结束,防止永久等待造成线程阻塞)。
finalize()方法是对象最后一次逃生的机会。在F-Queue 的队列中,GC会对其进行第二次小规模的标记。在这一步中,要是对象想要自救,那么可以将该对象与引用链上的任何一个对象相关联即可。
若在第二次被标记中,对象依旧没能逃生,那么该对象就会真正的被判死刑,会被GC 真正的回收掉。
过程分析如图所示
对象存活判定
注:任何对象的finalize()方法都只会被系统自动调用一次,也就是说连续的两次调用 finalize()方法,第一次会成功执行,后一次会失败。
接下来我们说一下关于 方法区的垃圾回收
Java虚拟机明确表示可以不要求虚拟机在方法区实现垃圾收集, 而且在方法区中进行垃圾收集的“性价比”一般比较低,其效率远低于堆的垃圾回收,即便如此,这部分的垃圾回收依旧十分有必要。
方法区的垃圾回收目标主要是:废弃常量和无用的类。
判断一个常量是否是废弃常量的方式比较简单:当一个常量对象不再任何地方被引用的时候,则被标记为废弃常量,这个常量可以被回收。
判断一个类是否是无用的类,需要同时满足以下三个条件:
1.Java堆中不存在该类的任何实例对象;
2.加载该类的类加载器已经被回收;
3.该类对应的java.lang.Class对象不在任何地方被引用,且无法在任何地方通过反射访问该类的方法。
当然,即便类满足上述条件,也仅仅是代表在一个有实现类卸载的JVM实现上,该类就会被卸载掉。相应的,这个类的单例对象自然也可以被回收掉,并不代表一定会回收。












网友评论