56.对象的finalization机制、finalize方法理解
1.对象的finalization
机制
Java
提供了finalization
机制来允许开发人员提供对象销毁之前自定义处理逻辑。- 垃圾回收一个对象之前,总会先调用这个对象的
finalize()
方法 finalize()
方法是Object
类中定义的,允许在任何子类中被重写,用于对象被回收时进行资源释放,例如,关闭数据库连接等等。- 不要主动的调用
finalize()
方法,应该交给垃圾回收机制来调用。
原因:
a)finalize()
可能导致对象复活
b)finalize()
执行时间没有保障,完全有GC
线程决定,极端情况下,若不发生GC
,finalize()
就不会被调用
c)糟糕的finalize()
会影响GC
的性能 JVM
中的对象可能出现的3
种状态。a)
可触及的:从根节点开始,可以到达这个对象b)
可复活的:对象的所有引用都被释放,但是对象可能在finalize()
被复活(例如:在finalize()
中又有新的引用指向该对象)。c)
不可触及的,对象的finalize()
被调用之后,对象没有复活,那么会进入不可触及的状态。不可触及的对象不可能被复活,因为finalize()
只会调用一次
只有不可触及的对象才能够被回收。
判断一个对象是否可以被回收:
- 如果
objA
到GC Roots
没有引用链,则进行第一次标记。(这里的标记意思是,对象是不可达的,对象可能是可复活的或者不可触及的。) - 进行筛选,判断对象是否需要执行
finalize()
方法1)
如果对象objA
没有重写finalize()
方法,或者finalize()
方法已经被虚拟机调用过,则虚拟机认为“没有必要执行finalize()
”,objA
被判定为不可触及的2)
如果objA
重写了finalize()
方法,且还未执行过,那么objA
会被插入到F-Queue
队列中,由一个虚拟机自动创建的、低优先级的Finalizer
线程触发其finalize()
方法。3)
finalize()
方法是对象逃脱死亡的最后机会,稍后GC
会对F-Queue
中的objA
对象进行第二次标记,如果objA
在finalize()
方法中与引用链上的任何一个对象建立了联系(也就是复活了),那么第二次标记时,objA
会被移出“即将回收”集合。之后,对象会再次出现没有引用存在的情况,在这个情况下,finalize()
方法不会被再次调用,对象会直接变成不可触及状态。因为,一个对象的finalize()
方法只会被调用一次。
演示对象的finalization
机制的例子:/** * 测试Object类中finalize()方法,即对象的finalization机制。 */ public class CanReliveObj { public static CanReliveObj obj;//类变量,属于 GC Root //finalize方法只能被调用一次 @Override protected void finalize() throws Throwable { super.finalize(); System.out.println("调用当前类重写的finalize()方法"); obj = this;//当前待回收的对象在finalize()方法中与引用链上的一个对象obj建立了联系。 obj是GC Roots,this是当前对象,也就是要被回收的对象。 } public static void main(String[] args) { try { obj = new CanReliveObj(); // 对象第一次成功拯救自己 obj = null; System.gc();//调用垃圾回收器。第一次GC的时候,会执行finalize方法,在finalize方法中,由于obj指向了this,obj变量是一个GC Root,要被回收的对象与引用链上的对象建立了又联系,所以对象被复活了 System.out.println("第1次 gc"); // 因为Finalizer线程优先级很低,暂停2秒,以等待它 Thread.sleep(2000); if (obj == null) { System.out.println("obj is dead"); } else { System.out.println("obj is still alive"); // 这句会输出 } System.out.println("第2次 gc"); // 下面这段代码与上面的完全相同,但是这次自救却失败了 obj = null; System.gc(); // 第二次调用GC,由于finalize只能被调用一次,所以对象会直接被回收 // 因为Finalizer线程优先级很低,暂停2秒,以等待它 Thread.sleep(2000); if (obj == null) { System.out.println("obj is dead"); // 这句会输出 } else { System.out.println("obj is still alive"); } } catch (InterruptedException e) { e.printStackTrace(); } } }