`

java finalize方法总结、GC执行finalize的过程

阅读更多

一.finalize的作用

        finalize()是Object的protected方法,子类可以覆盖该方法以实现资源清理工作,GC在回收对象之前调用该方法。
        finalize()与C++中的析构函数不是对应的。C++中的析构函数调用的时机是确定的(对象离开作用域或delete掉),但Java中的finalize的调用具有不确定性。
        不建议用finalize方法完成“非内存资源”的清理工作,但建议用于:

        a.清理本地对象(通过JNI创建的对象);

        b.作为确保某些非内存资源(如Socket、文件等)释放的一个补充:在finalize方法中显式调用其他资源释放方法。其原因可见下文[finalize的问题]

 

二.finalize的问题
        一些与finalize相关的方法,由于一些致命的缺陷,已经被废弃了,如System.runFinalizersOnExit()方法、Runtime.runFinalizersOnExit()方法。
        System.gc()与System.runFinalization()方法增加了finalize方法执行的机会,但不可盲目依赖它们。
        Java语言规范并不保证finalize方法会被及时地执行、而且根本不会保证它们会被执行。
        finalize方法可能会带来性能问题。因为JVM通常在单独的低优先级线程中完成finalize的执行。
        对象再生问题:finalize方法中,可将待回收对象赋值给GC Roots可达的对象引用,从而达到对象再生的目的。
        finalize方法至多由GC执行一次(用户当然可以手动调用对象的finalize方法,但并不影响GC对finalize的行为)。

 

三. finalize的执行过程(生命周期)

1.finalize大体流程

        当对象变成(GC Roots)不可达时,GC会判断该对象是否覆盖了finalize方法,若未覆盖,则直接将其回收。否则,若对象未执行过finalize方法,将其放入F-Queue队列,由一低优先级线程执行该队列中对象的finalize方法。执行finalize方法完毕后,GC会再次判断该对象是否可达,若不可达,则进行回收,否则,对象“复活”。
2.具体的finalize流程
        对象可由两种状态,涉及到两类状态空间,一是终结状态空间 F = {unfinalized, finalizable, finalized};二是可达状态空间 R = {reachable, finalizer-reachable, unreachable}。各状态含义如下:
        a.unfinalized:新建对象会先进入此状态,GC并未准备执行其finalize方法,因为该对象是可达的。

        b.finalizable:表示GC可对该对象执行finalize方法,GC已检测到该对象不可达。正如前面所述,GC通过F-Queue队列和一专用线程完成finalize的执行。
        c.finalized:表示GC已经对该对象执行过finalize方法。
        d.reachable:表示GC Roots引用可达。
        e.finalizer-reachable(f-reachable):表示不是reachable,但可通过某个finalizable对象可达。
        f.unreachable:对象不可通过上面两种途径可达
        状态变迁图:

        变迁说明:
        a.新建对象首先处于[reachable, unfinalized]状态(A)
        b.随着程序的运行,一些引用关系会消失,导致状态变迁,从reachable状态变迁到f-reachable(B, C, D)或unreachable(E, F)状态
        c.若JVM检测到处于unfinalized状态的对象变成f-reachable或unreachable,JVM会将其标记为finalizable状态(G,H)。若对象原处于[unreachable, unfinalized]状态,则同时将其标记为f-reachable(H)。
        d.在某个时刻,JVM取出某个finalizable对象,将其标记为finalized并在某个线程中执行其finalize方法。由于是在活动线程中引用了该对象,该对象将变迁到(reachable, finalized)状态(K或J)。该动作将影响某些其他对象从f-reachable状态重新回到reachable状态(L, M, N)。
        e.处于finalizable状态的对象不能同时是unreahable的,由第d点可知,将对象finalizable对象标记为finalized时会由某个线程执行该对象的finalize方法,致使其变成reachable。这也是图中只有八个状态点的原因。
        f.程序员手动调用finalize方法并不会影响到上述内部标记的变化,因此JVM只会至多调用finalize一次,即使该对象“复活”也是如此。程序员手动调用多少次不影响JVM的行为。
        g.若JVM检测到finalized状态的对象变成unreachable,回收其内存(I)。
        h.若对象并未覆盖finalize方法,JVM会进行优化,直接回收对象(O)。
        i.注:System.runFinalizersOnExit()等方法可以使对象即使处于reachable状态,JVM仍对其执行finalize方法。

 

四.代码示例

1.对象复活

public class GC {

    public static GC SAVE_HOOK = null;

    public static void main(String[] args) throws InterruptedException {
        SAVE_HOOK = new GC();
        SAVE_HOOK = null;
        System.gc();
        Thread.sleep(500);
        if (null != SAVE_HOOK) { //此时对象应该处于(reachable, finalized)状态
            System.out.println("Yes , I am still alive");
        } else {
            System.out.println("No , I am dead");
        }
        SAVE_HOOK = null;
        System.gc();
        Thread.sleep(500);
        if (null != SAVE_HOOK) {
            System.out.println("Yes , I am still alive");
        } else {
            System.out.println("No , I am dead");
        }
    }

    @Override
    protected void finalize() throws Throwable {
        super.finalize();
        System.out.println("execute method finalize()");
        SAVE_HOOK = this;
    }
}

        我们Debug上面代码,应该都是如下几种结果:

        结果一:

execute method finalize()
Yes , I am still alive
No , I am dead

        结果二:

No , I am dead
execute method finalize()
Yes , I am still alive

        结果三:

No , I am dead
No , I am dead
execute method finalize()

        因为System.gc();方法会启动一个守护线程执行finalize()方法,但由于线程调度随机,上面三种结果都有可能会出现,结果二即很好的展示了对象复活。



2.覆盖finalize方法以确保资源释放
        作为一个补充操作,以防用户忘记“关闭”资源,JDK中FileInputStream、FileOutputStream、Connection类均用了此”技术“,下面代码摘自FileInputStream类。

/**
 * Ensures that the <code>close</code> method of this file input stream is
 * called when there are no more references to it.
 *
 * @exception  IOException  if an I/O error occurs.
 * @see        java.io.FileInputStream#close()
 */
protected void finalize() throws IOException {
    if ((fd != null) &&  (fd != FileDescriptor.in)) {
        /* if fd is shared, the references in FileDescriptor
         * will ensure that finalizer is only called when
         * safe to do so. All references using the fd have
         * become unreachable. We can call close()
         */
        close();
    }
}

 

注:本文的目的并不是鼓励使用finalize方法,而是大致理清其作用、问题以及GC执行finalize的过程。

 

参考:

深入理解java的finalize http://zhang-xzhi-xjtu.iteye.com/blog/484934
The Finalizable Object  http://www.artima.com/interfacedesign/Finalizable.html

  • 大小: 5.1 KB
  • 大小: 15.2 KB
分享到:
评论

相关推荐

    Java中finalize()的用法

    finalize() 方法的调用机制是:在垃圾回收器准备回收对象时,首先调用 finalize() 方法,然后在下一次垃圾回收过程中,真正回收对象的内存。finalize() 方法可以在以下三种情况下被调用:1. 所有对象被 Garbage ...

    Java中finalize方法使用.doc

    在 Java 中,finalize 方法可以被重写,以便在对象被回收之前执行一些特定的操作。例如,在 finalize 方法中可以关闭文件、释放内存、断开网络连接等操作。 下面是一个使用 finalize 方法的示例代码: ```java ...

    【IT十八掌徐培成】Java基础第26天-03.JVM结构-finalize-gc.zip

    在本课程"【IT十八掌徐培成】Java基础第26天-03.JVM结构-finalize-gc"中,我们将深入探讨JVM的结构、`finalize`方法以及垃圾收集(Garbage Collection,简称GC)机制。以下是这些主题的详细阐述: 1. JVM结构: - ...

    优秀的Java程序员必须了解GC的工作原理

    2. **可达性问题**:`finalize()`方法执行后,对象可能再次变为可达状态,从而导致GC需要重新评估其可达性。 3. **非确定性调用**:`finalize()`方法可能根本不被调用,这使得依赖该方法进行清理的资源无法得到释放...

    Java垃圾回收机制的finalize方法实例分析

    Java垃圾回收机制的finalize方法实例分析 Java垃圾回收机制的finalize方法是垃圾回收机制中一个非常重要的概念,它可以帮助开发者更好地理解和掌握垃圾回收机制的工作机理。本文将通过实例形式分析finalize方法的...

    final, finally, finalize的区别

    当一个对象不再被引用且即将被垃圾回收器(GC)回收时,如果该对象实现了 `finalize` 方法,那么在 GC 执行前,会调用该对象的 `finalize` 方法。然而,`finalize` 的使用并不推荐,原因有以下几点: 1. **不可靠...

    简单理解Java的垃圾回收机制与finalize方法的作用

    总结来说,Java的垃圾回收机制和`finalize()`方法是为了解决内存管理问题而设计的,但使用时需谨慎,避免滥用。通常,遵循良好的编程习惯,如使用`try-finally`或`try-with-resources`来管理资源,可以更好地保证...

    java虚拟机中gc的基本原理 .docx

    但需要注意的是,JVM并不保证`finalize`一定会被调用,且每个对象的`finalize`方法最多只会被执行一次。因此,开发者不应过度依赖`finalize`进行资源清理,因为它会带来额外的性能开销,并可能导致不可预测的行为。...

    优秀Java程序员必须了解的GC工作原理

    `finalize`方法是Java中的一个重要概念,它是`Object`类的一个`protected`方法,用于在对象被垃圾回收前执行特定的清理操作。尽管`finalize`有时被误认为是C++中的析构函数,但它们之间存在显著差异。`finalize`不是...

    垃圾回收finalize的用处(算法 演示)

    当垃圾回收器确定一个对象不再被引用时,会尝试调用该对象的`finalize`方法,以便执行一些清理工作,如关闭文件、网络连接或释放非Java资源。需要注意的是,`finalize`方法的执行并不保证,而且不应该依赖于它来确保...

    Java9垃圾回收方法finalize() 原理解析

    Java9垃圾回收方法中的finalize()方法是一个特殊的方法,它是Object类中的方法,用于在类被GC回收时做一些处理操作。finalize()方法的主要作用是释放对象占用的资源,例如关闭文件、释放Socket等。但是,finalize()...

    从JVM的内存管理角度分析Java的GC垃圾回收机制.docx

    `finalize`是Java中Object类的一个受保护的方法,用于在对象被回收前执行一些清理工作。开发者可以通过覆盖这个方法来实现资源的释放。需要注意的是,`finalize`并不是自动调用的,且JVM并不保证每个对象的`finalize...

    Java SE编程入门教程 java GC(共6页).pptx

    Java提供了`finalize()`方法,这是一个在对象即将被垃圾回收时自动调用的方法,用于执行对象清理工作。但需要注意的是,依赖`finalize()`来进行必要的清理工作是不可靠的,因为JVM只有在内存压力较大时才会进行垃圾...

    Java基础总结基础部分

    ### Java基础总结基础部分 #### 运行时异常与一般异常的区别 异常是程序运行过程中可能出现的非正常状态。在Java中,异常大致分为两大类:运行时异常和非运行时异常(也称检查型异常)。 - **运行时异常**: - ...

    Java垃圾回收finalize()作用详解

    对于`finalize()`方法,Java有一个特殊的 finalize 队列,当对象被标记为可回收且其`finalize()`未被执行过时,会被放入这个队列。垃圾收集器会在下一次垃圾收集周期中调用这些对象的`finalize()`方法,然后才真正...

    java项目开发总结.docx

    * 对象的生命周期、垃圾回收、构造方法和 finalize 方法 三、异常处理 * 编译期错误和运行期错误的区分 * Exception、RuntimeException、checked exception 和 unchecked exception * try、catch、finally 语句和 ...

    JAVA程序员面试宝典笔记总结(刘磊版)

    - Java对象有一个`finalize()`方法,该方法可以在对象被垃圾回收之前执行。 - `System.gc()`和`Runtime.getRuntime().gc()`可以手动触发垃圾回收,但这并不是最佳实践。 #### 7. jar和war - `jar`(Java Archive)...

    Java面试总结

    Java面试总结涵盖了JavaSE到JavaEE的广泛知识点,其中包含Java基础概念和面向对象编程的特征,理解这些基础对于Java开发者而言至关重要。面试者必须熟悉Java中的异常处理机制、内存管理和集合框架。 面向对象编程的...

    一篇文章教你深入理解Java垃圾收集(GC)机制.docx

    GC主要关注的是Java堆和方法区这两部分内存,因为它们是动态分配和回收的。 1. **对象可回收性的判断** - 引用计数算法:此算法简单直观,但无法处理循环引用问题,例如对象A引用对象B,B引用A,两者引用计数都...

    Java企业级开发综合技能知识总结

    ### Java企业级开发综合技能知识总结 #### Java面向对象 1. **super()与this()的区别?** - `super()`用于调用父类构造器,必须作为子类构造器的第一条语句出现。 - `this()`用于调用本类的其他构造器,也必须...

Global site tag (gtag.js) - Google Analytics