首先垃圾收集算法要做两件事情:
1) 检测出垃圾对象
2)回收垃圾对象所使用的堆空间并还给程序
垃圾检测通常通过建立一个根对象的集合并且检查从这些根对象开始的可触及性来实现。对于程序来说,根对象总是可以访问的。从这个根对象开始,任何可以被触及的对象都被认为是活动对象,无法被触及的对象被认为是垃圾。
java虚拟机的根对象集合根据实现而不同,但是总会包含局部变量中的对象引用和栈帧的操作数栈(以及类变量中的对象引用)。另一个根对象的来源是被加载的类的常量池中的对象引用,比如字符串。还有一个来源是传递到本地方法中的,没有被本地方法释放的对象引用。另一个潜在的根对象的来源是,java虚拟机运行时数据区中从垃圾收集器的堆中分配的部分。
好下面进入主题,先看入下一段代码:
class Example1 {
protected void finalize() throws Throwable{
//......
super.finalize();
}
//......
}
该类就是自身含有一个对象终结方法finalize, Jvm在回收含有终结方法的垃圾对象时要完成的工作更加复杂。
存在终结方法时,JVM的垃圾收集器必须在每次回收时执行一些额外的操作。首先,垃圾收集器检测出不再被引用的对象(第一遍扫描)。然后,必须检测这些不再被引用的对象是否声明了终结方法,如果时间允许的话,可能垃圾收集器就在这个时间开始处理这些终结方法,执行完后,垃圾收集器又必须从根节点再次检测不再被引用的对象(第二边扫描),因为终结方法可能“复活”了某些不再被引用的对象,使得它们再次被引用了。最后,垃圾收集器才能释放那些在在两次扫描中发现的都没被引用的对象。
“每次对有终结方法对象的收集都要进行两遍的扫描会不会太影响效率呢?” 恩,很好的问题。
JVM早有准备了,在扫描到含有终结方法和运行这些终结方法之间,垃圾收集器可以有选择的插入一个步骤。当垃圾收集器执行了第一遍扫描后,并找到了一些不再被引用的对象需要需要执行终结时,它可以运行一次小型的追踪,从需要执行终结的对象开始(不是从根节点开始)。任何满足如下条件的对象——从跟节点开始不可触及和将要被终结的对象开始不可触及——这些对象不可能再执行终结方法时复活,它们可以立即被释放。
问题又来了“如果一个对象的终结方法被调用了,但是对象由于种种原因暂时还没销毁,还会不会再次被调用??” 哎。。
如果一个带有终结方法的对象不再被引用,并且它的终结方法运行过了,垃圾收集器必须使用某种方法(哪种方法还不清楚 ,见谅)记在这一点,而不能再次执行这个对象的终结方法。如果这个对象被它自己的或者其他对象的终结方法复活了,此时垃圾收集器必须像对待一个没有终结方法的对象一样对待它。
ok。。。。。。。