【问题标题】:Java and manually executing finalizeJava和手动执行finalize
【发布时间】:2010-09-06 22:17:31
【问题描述】:
如果我从我的程序代码中对一个对象调用finalize(),当垃圾收集器处理这个对象时,JVM 是否仍会再次运行该方法?
这是一个大概的例子:
MyObject m = new MyObject();
m.finalize();
m = null;
System.gc()
显式调用finalize() 是否会使JVM 的垃圾收集器不在对象m 上运行finalize() 方法?
【问题讨论】:
标签:
java
garbage-collection
finalize
【解决方案1】:
必须了解垃圾收集器(GC)工作流程才能了解finalize的功能。调用 .finalize() 不会调用垃圾收集器,也不会调用 system.gc。实际上,finalize 对编码器的帮助是将对象的引用声明为“未引用”。
GC 强制暂停 JVM 的运行操作,这会降低性能。在运行过程中,GC 会遍历所有引用的对象,从根对象(你的主方法调用)开始。可以通过手动将对象声明为未引用来减少此暂停时间,因为它会降低通过自动运行声明对象引用已过时的操作成本。通过声明 finalize(),coder 设置了对对象的引用废弃,这样在下次运行 GC 操作时,GC 运行将在不使用操作时间的情况下扫描对象。
引用:“在为一个对象调用 finalize 方法之后,不会采取进一步的行动,直到 Java 虚拟机再次确定不再有任何方法可以让任何尚未访问该对象的线程访问该对象。尚未死亡,包括其他准备完成的对象或类的可能操作,此时该对象可能被丢弃。”来自 java.Object.finalize() 上的 Java API 文档;
详细解释也可以查看:javabook.computerware
【解决方案2】:
根据这个简单的测试程序,即使你显式调用了 JVM,它仍然会调用 finalize():
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");
}
输出是:
开始
完成!
完成!
完成
那里的每个资源都说永远不会显式调用 finalize(),甚至几乎永远不会实现该方法,因为无法保证是否以及何时调用它。最好手动关闭所有资源。
【解决方案3】:
对于任何给定对象,JVM 永远不会多次调用 finalize 方法。无论如何,您都不应该依赖 finalize,因为不能保证它会被调用。如果您因为需要执行清理代码而调用 finalize,那么最好将其放入单独的方法中并使其显式,例如:
public void cleanUp() {
.
.
.
}
myInstance.cleanUp();