在Java中清理Object的最佳方法是什么?

时间:2009-09-04 17:44:50

标签: java

我们在Java中没有任何析构函数,就像我们在C ++中一样。

Q1。我们应该如何清理java中的任何对象。

Q2。是否有替代finally块。

Q3。有时我们必须从我们的班级中明确地调用第三方代码的初始化/终止,例如

public classs MyClass{
    public MyClass(){
        ThirdPartyInitialize();
    }

    protected void finalize(){
        ThirdPartyTerminate();
    }
}

这是正确的方法吗?

9 个答案:

答案 0 :(得分:15)

您通常无法自己“清理”Java对象。垃圾收集器决定何时清理对象。您可以通过将对象引用设置为null来指示何时完成对象引用,但通常只是让它超出范围就足够了。无论哪种方式,您仍然无法控制何时收集垃圾。

finally块用于执行操作,无论是否从try块抛出异常,并且是执行清理的最佳位置。通常,您只会清理非开放流等非对象资源。

finalize()不能保证被调用,因为在程序退出之前不保证会调用垃圾收集器。它不像C ++析构函数,因为C ++析构函数总是被调用,你可以依赖它们被调用。您不能依赖finalize()被调用。

所以1)使用finally块来释放非对象资源2)让垃圾收集器清理对象资源3)你可以通过将对象设置为垃圾收集器提示你已完成对象null如果在长时间运行的方法中使用它。

答案 1 :(得分:5)

如果您的计划也关闭了,您还可以在程序中添加shutdown hook

//add shutdown hook
Runtime.getRuntime().addShutdownHook(new Thread() {
    public void run() {
        ThirdPartyTerminate();
    }
});

答案 2 :(得分:2)

清理对象后的最佳方法是删除对象。

最后,可以使用Execute Around习语来抽象块。

应该避免终结者。他们可能不会马上被召唤。无论如何都应该进行清理。它们相对较慢。如果要编写低级资源包装器(例如,文件句柄),如果性能不是很关键,则可能需要添加一个作为安全网。

答案 3 :(得分:2)

两种语法糖选项:

1)Lombok中有一个@Cleanup注释,大部分类似于C ++析构函数(more):

@Cleanup
ResourceClass resource = new ResourceClass();

2)还有try-with-resources陈述。例如:

try (BufferedReader br = new BufferedReader(new FileReader(path))) {
  System.out.println(br.readLine());
}

答案 4 :(得分:1)

Here's关于终结者的良好见解。

答案 5 :(得分:1)

当您不再需要时,可以通过删除对象的引用来清理对象。你不必明确地这样做。显式清理需要将引用设置为null,从而向垃圾收集器提供可以收集对象的提示。此提示有效,因为每个对象的内部引用计数都是在内部维护的。 例如


C a = new C(); //create an object of class C and assign it to 'a'
a = new C(); //create another object of class C and assign it to 'a'. The older object is no longer referred to. It is now eligible for GC.

finalize()有更好的替代方案,具体取决于finalize()对你的情况有多大帮助。

通常,最佳做法是在API中提供类似close()或disposeResources()的方法,这将允许调用者帮助API自行清理。例如,java.sql.Connection class does this。这比finalize()方法更好,因为JVM将调用finalize()方法。通常,finalize()方法将由JVM中的低优先级线程运行,从而导致某些奇怪的错误。

对于Connection类,等待JVM执行最终化确实在许多应用程序中证明是昂贵的,因为数据库一次只能接受这么多连接。因此,大多数程序员将在Connection对象上显式调用close()。

在你的情况下,它应该转换成类似的东西(在这种情况下,finally块肯定会一直运行)


try
{
 ThirdPartyInitialize();
 // use third party component in this try block
}
finally
{
 ThirdPartyTerminate();
}

这类似于大多数情况下Connection类的使用方式。

答案 6 :(得分:1)

您可以在Java 9中使用java.lang.ref.Cleaner

答案 7 :(得分:0)

finalize与析构函数类似,但是,如果你使用try ... finally块资源,那么你可以打开一个资源,在finally块中你关闭资源。

当块退出时,无论是正常还是抛出异常,都会调用finally块。

Finalize对于资源管理是有风险的,因为你不知道什么时候会被调用,如果它关闭了一个也已经完成的对象,那么它可能需要一段时间。

finally块是更好的方法。

答案 8 :(得分:-1)

你的Java中的对象真的永远不需要“清理”,GC正常工作。几乎每次我在代码中看到someObject = null时,都会有人不知道他们在做什么。这有一个理论上的例子,但它确实是一个边缘情况,通常更好地处理其他方式,如最近添加的资源尝试。

如果您在不再使用某个对象时需要清理外部资源,则这是另一回事。

有一些“引用”类将保存一个特殊类型的引用类 - 它不会停止垃圾收集,但可以在类被垃圾收集时通知您(如果您愿意,可以通过回调)。查找WeakReference,PhantomReference等。

这些是可靠的,并且比实际的“finalize”方法更加确定,因为回调在你的类之外,所以你最终不会在一些预先删除或半删除状态下执行一个方法以及可能导致的问题。