关于垃圾回收:Java和手动执行finalize

关于垃圾回收:Java和手动执行finalize

Java and manually executing finalize

如果我从程序代码中的对象上调用finalize(),那么当垃圾回收器处理该对象时,JVM是否还会再次运行该方法?

这是一个大概的例子:

1
2
3
4
5
6
7
MyObject m = new MyObject();

m.finalize();

m = null;

System.gc()

finalize()的显式调用是否会使JVM的垃圾回收器不对对象m运行finalize()方法?


根据这个简单的测试程序,即使您显式调用了JVM,JVM仍将对finalize()进行调用:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
private static class Blah
{
  public void finalize() { System.out.println("finalizing!"); }
}

private static void f() throws Throwable
{
   Blah blah = new Blah();
   blah.finalize();
}

public static void main(String[] args) throws Throwable
{
    System.out.println("start");
    f();
    System.gc();
    System.out.println("done");
}

输出为:

start
finalizing!
finalizing!
done

那里的每个资源都说永远不要显式地调用finalize(),甚至几乎永远都不会实现该方法,因为无法保证是否以及何时调用它。最好只手动关闭所有资源。


必须了解垃圾收集器(GC)工作流程才能了解完成的功能。调用.finalize()不会调用垃圾回收器,也不会调用system.gc。实际上,最终确定将有助于编码人员将对象的引用声明为"未引用"。

GC强制中止JVM的运行操作,这会降低性能。在运行期间,GC将从根对象(您的主要方法调用)开始遍历所有引用的对象。可以通过手动将对象声明为未引用来减少该挂起时间,因为这样可以减少自动运行过时声明对象引用已过时的操作成本。通过声明finalize(),编码器将对对象的引用设置为作废,因此在下一次GC操作时,GC运行将不使用操作时间就清除对象。

Quote:"在为对象调用finalize方法之后,在Java虚拟机再次确定不再有任何方法可以由尚未死亡的任何线程访问该对象之前,不采取进一步的措施,包括准备好完成的其他对象或类可能采取的措施,此时可能会丢弃该对象。"从java.Object.finalize()上的Java API文档中获取信息。

有关详细说明,您还可以检查:javabook.computerware


JVM对于任何给定对象都不会多次调用finalize方法。无论如何,您都不应该依赖finalize,因为不能保证会调用它。如果由于需要执行清理代码而调用finalize,则最好将其放入一个单独的方法中并使其明确,例如:

1
2
3
4
5
6
7
public void cleanUp() {
  .
  .
  .
}

myInstance.cleanUp();


推荐阅读