0

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

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. 当对象被垃圾回收时调用终结器。这意味着它不应该调用'bar' bar 是如何被打印出来的。

4

6 回答 6

3

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

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

当对象被垃圾回收时调用终结器。这意味着它不应该调用'bar' bar 是如何被打印出来的。

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

于 2013-08-11T02:15:42.520 回答
2

你不应该给finalize()自己打电话。JVM 在它应该这样做的时候调用它。此方法不会导致对象被 GC 处理,而是会进行清理,这又不是普通的凡人代码应该调用的东西。

于 2013-08-11T02:08:07.550 回答
1

The finalize in Object.java is an empty function, Where is the heavy work of cleaning the object happening ?

Inside the JVM, as part of the garbage collector. You don't have access to any of this logic.

Finalizer is called when object is garbage collected. Which means it should not call 'bar' How is bar still being printed.

Not exactly. finalize() is called at any point between the moment the object has no references (and thus is ready for collection) and the moment the VM decides to effectively reclaim it, but before effectively doing it. This is important because finalize() could not only print "bar", but even establish references (by executing AClass.aStaticField= this ;, as a very simple example) that make the object or other objects previously eligible for collection again "alive". For this reason, the object's eligibility for garbage collection is checked again after finalize() and collection possibly aborted. By doing this, objects can refuse to be garbage collected, but not forever (see below).

Additional ideas that could help understanding finalize()?

  1. It's not equivalent to a destructor at all.
  2. It exists mainly for historical reasons. The original idea was to give objects a chance of cleaning up resources (TCP connections, open files, etc.) before being collected. However, the period that can pass between object "release" and finalize() is so variable that explicit resource de-allocation through close() methods became the preferred ("Javatic"?) way and finalize() use has been discouraged. In fact, many JVMs do not call any finalize() method when terminating.
  3. One good example of the preference I mention above is the "try with resources" construct introduced in Java 7. In contrast, nothing has been done to correct the challenges presented by finalize(). Ever.
  4. The ability of finalize() to "resurrect" not only its own object, but also other objects has consequences not fully specified. What has been specified is: "The finalize method is never invoked more than once by a Java virtual machine for any given object.". This means that if finalize() "resurrects" its own object, it will not be called a second time even the object is ready for collection again. Very curious behavior to say the least. Random in fact if two objects interplayed this way, as Java doesn't guarantee any order while collecting objects.
  5. In summary: do not use finalize(). If you did, you would be one of the first persons depending on it for anything. The idea was good, in principle, but there was no way of anticipating the consequences that became apparent in time. Do define explicit close() methods for resource cleanup. In some cases, cleanup threads that monitor resource usage can also be useful.

PS: Something very similar happened with Thread.suspend(), Thread.resume(), Thread.stop(), and Thread.destroy(). Very nice ideas that practice proved a nightmate in terms of application and JVM stability. The only difference is that these Thread methods have been officially deprecated because their impact is (debatably) bigger.

于 2013-08-11T03:16:29.590 回答
0

当对象即将被收集时,垃圾收集器会调用 finalize。

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

于 2013-08-11T02:08:25.520 回答
0

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

这是 Object 类中的一个空方法,但如果您要利用它的目的,那么您需要在您的类中覆盖它。

当对象被垃圾回收时调用终结器。这意味着它不应该调用'bar' bar 是如何被打印出来的。

在对象被垃圾收集之前,jvm 会调用 finalize 方法。但是作为一个简单的方法,你总是可以直接调用它。但是直接调用 finalize 不会使对象准备好或得到垃圾收集。因此这样做:

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

仍然可以工作,因为inDo对象仍然被引用或处于活动状态并且没有被垃圾收集。

于 2013-08-11T02:08:25.647 回答
0
  1. 如果您想查看完成工作,请运行此测试

    公共类Test1 {

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

    }

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

  1. finalize 是来自 JVM 的回调,应该用一些有意义的实现来覆盖它,例如 java.io.FileInputStream 实现 finalize 以关闭程序未能关闭的 FileInputStream。Effective Java Item.7 Avoid finalizers 中有一篇文章详细解释了 finalize 的问题
于 2013-08-11T03:38:17.950 回答