调用终结器真的去了哪里

时间:2013-08-11 02:04:24

标签: java finalizer

现在,我写了一个简单的代码。

public class ToDo {

    ToDo instance;

    public ToDo () {

    }

    void foo() {
        System.out.println("foo.");
    }

    void bar() {
        System.out.println("bar.");
    }

    public static void main(String args[]) throws Throwable {

        ToDo inDo = new ToDo();
        inDo.foo();
        inDo.finalize();
        inDo.bar();
    }
}
  1. Object.java中的finalize是一个空函数,清理对象的繁重工作在哪里?

  2. 在对象被垃圾回收时调用Finalizer。这意味着它不应该调用'bar'如何仍然打印条。

6 个答案:

答案 0 :(得分:3)

  

Object.java中的最终结果是一个空函数,清理对象的繁重工作在哪里?

Java中的对象通常不会被“清理”。在C ++中,析构函数最常见的任务是释放已分配的内存,但在Java中,VM负责垃圾收集未使用的分配。终结器可用于释放非托管资源,例如本机OS UI组件,但您不能依赖它们来处理此作业,因为它们可能在对象停止使用后很长时间被调用,或者根本不会被调用。相反,您应该有一个方法,例如dispose()close()(请参阅Closeable),您可以选择从终结器调用该方法作为一种安全网,但是您的客户端代码应该负责打电话。

  

当对象被垃圾收集时调用Finalizer。这意味着它不应该调用'bar'如何仍然打印条。

在终结器完成之前,对象仍然有效,因此调用bar是可以接受的。如上所述,您可以使用终结器调用清理方法,以防客户端打开一些东西。

答案 1 :(得分:2)

您不应该自己致电finalize()。如果它应该这样做,JVM会调用它。这种方法不会导致对象被GC化,而是进行清理,而且,这并不是普通凡人代码应该调用的东西。

答案 2 :(得分:1)

  

Object.java中的finalize是一个空函数,清理对象的繁重工作在哪里?

在JVM内部,作为垃圾收集器的一部分。您无权访问任何此逻辑。

  

当对象被垃圾收集时调用Finalizer。这意味着它不应该调用'bar'如何仍然打印条。

不完全是。在对象没有引用(因此准备好收集)和VM决定有效回收它的那一刻之间,但在有效地执行它之前的任何时刻都会调用finalize()。这很重要,因为finalize()不仅可以打印“bar”,而且甚至可以建立引用(通过执行AClass.aStaticField= this ;,作为一个非常简单的示例),使对象或其他对象先前有资格再次收集“活着” ”。因此,在finalize()之后再次检查对象的垃圾收集资格,并且可能中止收集。通过这样做,对象可以拒绝垃圾收集,但不是永远收集(见下文)。

  

有助于理解finalize()的其他想法?

  1. 它不等同于的析构函数
  2. 主要是出于历史原因。最初的想法是在收集之前让对象有机会清理资源(TCP连接,打开文件等)。但是,可以在对象“release”和finalize()之间传递的时间段是如此可变,以至于通过close()方法显式资源取消分配成为首选(“Javatic”?)方式和finalize()使用已被劝阻。实际上,许多JVM在终止时不会调用任何finalize()方法。
  3. 我在上面提到的偏好的一个很好的例子是Java 7中引入的“try with resources”结构。相比之下,没有采取任何措施来纠正finalize()提出的挑战。如初。
  4. finalize()不仅“恢复”自己的对象,而且还有其他对象的“复活”能力的后果尚未完全明确。 具有指定的是:“对于任何给定对象,Java虚拟机永远不会多次调用finalize方法。”。这意味着如果finalize()“复活”其自己的对象,即使对象已准备好再次收集,也不会再次调用它。至少可以说非常奇怪的行为。实际上是随机的,如果两个对象以这种方式相互交错,因为Java在收集对象时不保证任何顺序。
  5. 总结:使用finalize()。如果你这样做了,你将成为第一批依赖它的人之一。原则上,这个想法很好,但没有办法预测随着时间变得明显的后果。 为资源清理定义显式close()方法。在某些情况下,监视资源使用情况的清理线程也很有用。
  6. PS:Thread.suspend()Thread.resume()Thread.stop()Thread.destroy()发生了类似情况。非常好的想法,在应用程序和JVM稳定性方面,练习证明是一个夜晚。唯一的区别是这些Thread方法已被正式弃用,因为它们的影响(可辩解地)更大。

答案 3 :(得分:0)

当要收集对象时,垃圾收集器会调用

你调用finalize根本没有任何效果。 (这就像调用任何其他方法一样)。

答案 4 :(得分:0)

  

Object.java中的finalize是一个空函数,其中重要的是   清洁物体的工作是什么?

这是Object类中的一个空方法,但如果你要使用它的目的,那么你需要在你的类中重写它。

  

当对象被垃圾收集时调用Finalizer。这意味着它   不应该打电话给' bar'如何打印酒吧。

在对象收集垃圾之前,jvm会调用

finalize方法。但作为一种简单的方法,您可以随时直接调用它。但是直接调用finalize并不会使对象准备好或收集垃圾。因此这样做:

    inDo.finalize();
    inDo.bar();

仍然有效,因为inDo对象仍然被引用或激活而不是垃圾回收。

答案 5 :(得分:0)

  1. 如果您想查看完成工作,请运行此测试

    公共类Test1 {

    protected void finalize()  {
        System.out.println("finalize");
    }
    
    public static void main(String[] args) throws Exception {
        new Test1();
        System.gc();
    }
    

    }

  2. 请注意,System.gc不保证GC会运行,但它始终在我的HotSpot VM上运行。

    1. finalize是来自JVM的回调,它应该被一些有意义的实现覆盖,例如java.io.FileInputStream实现finalize来关闭FileInputStream,该程序无法关闭。在Effective Java Item.7中有一篇文章。避免使用终结器来解释详细结束的问题