JVM虚拟机垃圾回收中的finalize方法作用

        GC(垃圾回收)最主要的作用是回收程序中不再使用的内存。当使用new创建对象后, Java虚拟机会给其分配一块内存资源, 当对象无用的时候Java的垃圾回收器负责回收无用对象占用的内存资源。如果你的对象并非用new获取了一块“特殊”内存,垃圾回收只知道释放那些由New分配的内存, 它并不知道如何释放对象的“特殊内存”,为了应对这种情况,Java允许在类中命名finalize方法

        GC垃圾回收过处理可达性分析算法中不可达的对象被标记成需要回收, 一但垃圾回收器准备释放对象占用的内存会经理两个过程

  • finalize方法没有被虚拟机调用过,那么先调用对象的finalize方法。本次不再处理等待下一次垃圾回收处理
  • finalize方法调用过一次后,再次垃圾回收释放对象占用的内存

       第一个过程中, 如果这个对象被判定为有必要执行finalize()方法,那么这个对象将会放置在一个叫做F-Queue的队列之中,并在稍后由一个由虚拟机自动建立的、低优先级的Finalizer线程去执行它。这里所谓的“执行”是指虚拟机会触发这个方法,但并不承诺会等待它运行结束,这样做的原因是,如果一个对象在finalize()方法中执行缓慢,或者发生了死循环(更极端的情况),将很可能会导致F-Queue队列中其他对象永久处于等待,甚至导致整个内存回收系统崩溃。finalize()方法是对象逃脱死亡命运的最后一次机会,稍后GC将对F-Queue中的对象进行第二次小规模的标记,如果对象要在finalize()中成功拯救自己——只要重新与引用链上的任何一个对象建立关联即可,譬如把自己(this关键字)赋值给某个类变量或者对象的成员变量,那在第二次标记时它将被移除出“即将回收”的集合;如果对象这时候还没有逃脱,那基本上它就真的被回收了

public class FinalizeEscapeGC {
    public static FinalizeEscapeGC SAVE_HOOK = null;

    public void isAlive() {
        System.out.println("yes,i am still alive:)");
    }

    @
            Override
    protected void finalize() throws Throwable {
        super.finalize();
        System.out.println("finalize mehtod executed!");
        FinalizeEscapeGC.SAVE_HOOK = this;
    }

    public static void main(String[] args) throws Throwable {
        SAVE_HOOK = new FinalizeEscapeGC();
        //对象第一次成功拯救自己
        SAVE_HOOK = null;
        System.gc();
        //因为finalize方法优先级很低,所以暂停0.5秒以等待它
        System.out.println("sleep 500");
        Thread.sleep(500);
        System.out.println("after sleep 500");
        if (SAVE_HOOK != null) {
            SAVE_HOOK.isAlive();
        } else {
            System.out.println("no,i am dead:(");
        }
        //下面这段代码与上面的完全相同,但是这次自救却失败了
        SAVE_HOOK = null;
        System.gc();
        //因为finalize方法优先级很低,所以暂停0.5秒以等待它
        Thread.sleep(500);
        if (SAVE_HOOK != null) {
            SAVE_HOOK.isAlive();
        } else {
            System.out.println("no,i am dead:(");
        }
    }

}

从上面用例看出,第一次垃圾回收候调用finalize方法并没有被回收, 第二次回收才被回收。

       虽然finalize()方法可以在被对象销毁的时候调用,但是不建议把清理对象某些行为的在finalize()方法中执行, 因为这个方法的触发条件是GC操作,如果没有GC操作这个操作就不会被调用。《Java编程思想》里提到过一个例子: 某个对象将图绘制在屏幕上,在finalize()方法中增加了擦除功能,目的是当垃圾回收时执行finallize()方法的时候擦除图形,但是这个操作必须要垃圾回收才会执行,如果垃圾回收没有发生,那么图像就会一直保存在内存里。因此不能指望finallize, 更好的做法是在对象中明确擦除的行为, 当需要擦除的时候明确调用该行为

    

上一篇:JVM如何用Eclipse Memory Analyzer分析堆内存溢出 

猜你喜欢

转载自blog.csdn.net/Beijing_L/article/details/120185907
今日推荐