假设我已经创建了一些带有 close() 方法的资源类来清理资源,如果有人忘记调用 close() 我想覆盖 finalize() 以释放资源(并打印警告) .如何正确完成这项工作?
- 是否仅推荐用于 native (JNI 分配的)资源?
- 如果您使用终结器对另一个已终结对象的引用,会发生什么情况?如果存在循环依赖关系,我看不出垃圾收集器如何阻止您访问其终结器可能已被执行的对象。
- 除了覆盖 finalize() 以检测和/或处理资源泄漏,是否有更好的替代方法?
- 在实现终结器时还有其他需要注意的陷阱吗?
注意:我知道使用 finalize() 通常是个坏主意,而且不能保证一定会调用它,还有其他几个问题在讨论这个问题。这个问题专门关于如何在 Java 中实现终结器,而不是关于为什么您应该(或不应该)。
最佳答案
在effective java (2nd edition) ,Joshua 在第 7 项中详细介绍了如何执行此操作。他首先建议您几乎不应该使用 finalizer
。但是,使用它的一个原因是只打印一条日志语句,说明您有资源泄漏。他说,这样做的缺点之一是有人可以扩展你的类而没有正确调用 super 终结器。所以他建议在子类中做这样的事情:
// Manual finalizer chaining
@Override protected void finalize() throws Throwable {
try {
... // Finalize subclass state
} finally {
super.finalize();
}
}
这是为了确保如果当前类中出现问题,finally
仍将被调用。这可能是一个糟糕的解决方案,因为它取决于对你的类进行子类化的人。另一种解决方案是使用守护对象文件来完成此操作。这看起来像:
// Finalizer Guardian idiom
public class Foo {
// Sole purpose of this object is to finalize outer Foo object
private final Object finalizerGuardian = new Object() {
@Override protected void finalize() throws Throwable {
... // Finalize outer Foo object
}
};
... // Remainder omitted
}
这是一种更简洁的方法,因为您知道没有人可以覆盖该功能。
关闭资源的建议方法仍然是实现 Closeable
并确保它由用户关闭。正如 Josuha 建议的那样,您不应在 finalize
方法中执行任何时间敏感的操作。 JVM 可能会选择在将来的某个时间运行它。如果您依赖这种方法来进行提交或做一些重要的事情,那么这是一个坏主意。
关于java - 如何正确实现终结器以检测 Java 中的资源泄漏,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/12461995/