java finalize()方法
java中的finalize()方法
首先,finallize()方法是Object类中的方法,在GC准备释放对象占用的内存之前,必须执行finalize()方法
在Object类中的定义如下:
finalize()方法什么时候调用
在java中finalize()并不会每次都及时执行,因为GC的自动回收机制,导致垃圾回收的时机具有不确定性,jvm会在适当的时机对垃圾对象进行处理,因此,是无法保证finalize()方法 被及时执行的,甚至无法保证会被执行,程序可能始终无法触发垃圾回收
例子,
public class TestFinalize {
@Override
protected void finalize() throws Throwable{
System.out.println("finalize()方法执行了");
}
public static void main(String[] args) {
TestFinalize tf = new TestFinalize();
tf = null;//令tf为null,让GC对其进行回收
}
//结果无输出
我们重写finalize()方法,让它在执行时输出一句话,我们创建一个对象,对它赋
值null,这样GC会把这个对象判定为垃圾,执行后结果无输出,说明finalize()方法并不是及时执行的。
public class TestFinalize {
@Override
protected void finalize() throws Throwable{
System.out.println("finalize()方法执行了");
}
public static void main(String[] args) {
TestFinalize tf = new TestFinalize();
tf = null;//令tf为null,让GC对其进行回收
System.gc();//程序员手动请求gc
}
//输出finalize()方法执行了
当程序员手动请求gc之后,可以发现finalize()方法成功执行了。
由于java的gc机制并不需要我们程序员过多去关心内存动态的问题,所以finalize()方法一般情况下都不会去使用。什么情况下使用呢?一般是在释放非java资源的时候使用,
比如连的接数据库、打开的文件,或者调用本地非java方法(native)方法的时候分配的内存。由于finalize()方法调用时机的并不确定性,成功回收一个对象所花费的时间是任意长的,而这肯定不符合我们想要立即释放占用的资源的初衷,依赖finalize()方法的后果就是可能出现在资源耗尽之前,gc仍未触发的现象。并且,如果我们对finalize()方法进行重写也增加回收对象时的操作,从而延长了回收时间。所以,一般我们关闭文件流,都是用close()方法去关闭,而不是用finalize()去释放资源。
finalize的生命周期
finalize的大致流程,当对象变成GC Roots不可达的时候,GC就会判断该对象是否覆盖了finalize方法,如果没有覆盖,则会直接将其回收,否则,如果对象没有执行过finalize方法,会将其放入F-Queue队列,由一低优先级线程执行该队列中对象的finalize方法。执行完之后,GC会再次判断该对象是否可达,如果不可达则会直接进行回收,否则,将不会对其进行回收,对象“复活”。