一.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
相关推荐
finalize() 方法的调用机制是:在垃圾回收器准备回收对象时,首先调用 finalize() 方法,然后在下一次垃圾回收过程中,真正回收对象的内存。finalize() 方法可以在以下三种情况下被调用:1. 所有对象被 Garbage ...
在 Java 中,finalize 方法可以被重写,以便在对象被回收之前执行一些特定的操作。例如,在 finalize 方法中可以关闭文件、释放内存、断开网络连接等操作。 下面是一个使用 finalize 方法的示例代码: ```java ...
在本课程"【IT十八掌徐培成】Java基础第26天-03.JVM结构-finalize-gc"中,我们将深入探讨JVM的结构、`finalize`方法以及垃圾收集(Garbage Collection,简称GC)机制。以下是这些主题的详细阐述: 1. JVM结构: - ...
2. **可达性问题**:`finalize()`方法执行后,对象可能再次变为可达状态,从而导致GC需要重新评估其可达性。 3. **非确定性调用**:`finalize()`方法可能根本不被调用,这使得依赖该方法进行清理的资源无法得到释放...
Java垃圾回收机制的finalize方法实例分析 Java垃圾回收机制的finalize方法是垃圾回收机制中一个非常重要的概念,它可以帮助开发者更好地理解和掌握垃圾回收机制的工作机理。本文将通过实例形式分析finalize方法的...
当一个对象不再被引用且即将被垃圾回收器(GC)回收时,如果该对象实现了 `finalize` 方法,那么在 GC 执行前,会调用该对象的 `finalize` 方法。然而,`finalize` 的使用并不推荐,原因有以下几点: 1. **不可靠...
总结来说,Java的垃圾回收机制和`finalize()`方法是为了解决内存管理问题而设计的,但使用时需谨慎,避免滥用。通常,遵循良好的编程习惯,如使用`try-finally`或`try-with-resources`来管理资源,可以更好地保证...
但需要注意的是,JVM并不保证`finalize`一定会被调用,且每个对象的`finalize`方法最多只会被执行一次。因此,开发者不应过度依赖`finalize`进行资源清理,因为它会带来额外的性能开销,并可能导致不可预测的行为。...
当垃圾回收器确定一个对象不再被引用时,会尝试调用该对象的`finalize`方法,以便执行一些清理工作,如关闭文件、网络连接或释放非Java资源。需要注意的是,`finalize`方法的执行并不保证,而且不应该依赖于它来确保...
`finalize`方法是Java中的一个重要概念,它是`Object`类的一个`protected`方法,用于在对象被垃圾回收前执行特定的清理操作。尽管`finalize`有时被误认为是C++中的析构函数,但它们之间存在显著差异。`finalize`不是...
Java9垃圾回收方法中的finalize()方法是一个特殊的方法,它是Object类中的方法,用于在类被GC回收时做一些处理操作。finalize()方法的主要作用是释放对象占用的资源,例如关闭文件、释放Socket等。但是,finalize()...
`finalize`是Java中Object类的一个受保护的方法,用于在对象被回收前执行一些清理工作。开发者可以通过覆盖这个方法来实现资源的释放。需要注意的是,`finalize`并不是自动调用的,且JVM并不保证每个对象的`finalize...
Java提供了`finalize()`方法,这是一个在对象即将被垃圾回收时自动调用的方法,用于执行对象清理工作。但需要注意的是,依赖`finalize()`来进行必要的清理工作是不可靠的,因为JVM只有在内存压力较大时才会进行垃圾...
### Java基础总结基础部分 #### 运行时异常与一般异常的区别 异常是程序运行过程中可能出现的非正常状态。在Java中,异常大致分为两大类:运行时异常和非运行时异常(也称检查型异常)。 - **运行时异常**: - ...
对于`finalize()`方法,Java有一个特殊的 finalize 队列,当对象被标记为可回收且其`finalize()`未被执行过时,会被放入这个队列。垃圾收集器会在下一次垃圾收集周期中调用这些对象的`finalize()`方法,然后才真正...
* 对象的生命周期、垃圾回收、构造方法和 finalize 方法 三、异常处理 * 编译期错误和运行期错误的区分 * Exception、RuntimeException、checked exception 和 unchecked exception * try、catch、finally 语句和 ...
- Java对象有一个`finalize()`方法,该方法可以在对象被垃圾回收之前执行。 - `System.gc()`和`Runtime.getRuntime().gc()`可以手动触发垃圾回收,但这并不是最佳实践。 #### 7. jar和war - `jar`(Java Archive)...
Java面试总结涵盖了JavaSE到JavaEE的广泛知识点,其中包含Java基础概念和面向对象编程的特征,理解这些基础对于Java开发者而言至关重要。面试者必须熟悉Java中的异常处理机制、内存管理和集合框架。 面向对象编程的...
GC主要关注的是Java堆和方法区这两部分内存,因为它们是动态分配和回收的。 1. **对象可回收性的判断** - 引用计数算法:此算法简单直观,但无法处理循环引用问题,例如对象A引用对象B,B引用A,两者引用计数都...
### Java企业级开发综合技能知识总结 #### Java面向对象 1. **super()与this()的区别?** - `super()`用于调用父类构造器,必须作为子类构造器的第一条语句出现。 - `this()`用于调用本类的其他构造器,也必须...