java - 如何正确实现终结器以检测 Java 中的资源泄漏

标签 java resources garbage-collection finalizer

假设我已经创建了一些带有 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/

相关文章:

java - Spring 与 Java DSL 集成中的 Bean 和方法名称与 lambda

java - 关于我尝试读取 .FIT 文件时的异常

java - 开始使用自定义 JXTA PeerGroup

android - 使用复数以 ResourcesNotFoundException 结尾

Java 匿名类和垃圾收集器

java - 在 aws 服务器上启动 tomcat 8 的问题

java - 运行测试时从项目根目录而不是模块加载 Spring Boot 文件系统资源/配置

c - 在构建时更新资源文件中的 FILEVERSION

java - 在matlab中使用java类的清理问题

objective-c - Cocoa 网络流和垃圾收集器