Warning: file_get_contents(/data/phpspider/zhask/data//catemap/5/date/2.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
如何在Java中正确实现用于检测资源泄漏的终结器_Java_Resources_Garbage Collection_Finalizer - Fatal编程技术网

如何在Java中正确实现用于检测资源泄漏的终结器

如何在Java中正确实现用于检测资源泄漏的终结器,java,resources,garbage-collection,finalizer,Java,Resources,Garbage Collection,Finalizer,假设我创建了一个资源类,它使用close()方法清理资源,如果有人忘记调用close(),我想重写finalize()释放资源(并打印警告)。如何正确地做到这一点 是否只建议本机(JNI分配的)资源使用 如果使用来自终结器的对已终结的另一个对象的引用,会发生什么情况?如果存在循环依赖关系,我看不出垃圾收集器如何阻止您访问可能已执行终结器的对象 在检测和/或处理资源泄漏时,除了覆盖finalize()之外,还有其他更好的方法吗 在实现终结器时还需要注意哪些陷阱 注意:我知道使用finalize

假设我创建了一个资源类,它使用close()方法清理资源,如果有人忘记调用close(),我想重写finalize()释放资源(并打印警告)。如何正确地做到这一点

  • 是否只建议本机(JNI分配的)资源使用
  • 如果使用来自终结器的对已终结的另一个对象的引用,会发生什么情况?如果存在循环依赖关系,我看不出垃圾收集器如何阻止您访问可能已执行终结器的对象
  • 在检测和/或处理资源泄漏时,除了覆盖finalize()之外,还有其他更好的方法吗
  • 在实现终结器时还需要注意哪些陷阱
注意:我知道使用finalize()通常是个坏主意,而且它也不能保证被调用,还有其他几个问题正在讨论这个问题。这个问题是关于如何在Java中实现终结器的,而不是关于为什么应该(或不应该)实现终结器的问题。

在中,Joshua在第7项中详细介绍了如何实现终结器。他首先建议您几乎不应该使用
finalizer
s。但是,使用它只打印一条日志语句的一个原因是,您有一个资源泄漏。他说,这样做的一个缺点是有人可以扩展你的类,而不能正确地调用超级终结器。因此,他建议在子类中执行类似的操作:

// Manual finalizer chaining
   @Override protected void finalize() throws Throwable {
       try {
           ... // Finalize subclass state
       } finally {
           super.finalize();
   } 
}
这是为了确保如果在当前类中出现故障,
finally
仍将被调用。这可能是一个糟糕的解决方案,因为它取决于对类进行子类化的人。另一种解决方案是使用guardian对象文件来完成此操作。这看起来像:

// 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可能会选择在将来某个时候运行它。如果您依赖此方法来执行提交或其他重要操作,那么这是一个坏主意

是否只建议本机(JNI分配的)资源使用

不可以。您的用例对于终结器也是有效的。我的意思是记录资源泄漏

如果访问另一个已被访问的Java对象,会发生什么 在终结器中终结


如果您仍然可以访问它,则它尚未最终确定。或者我在你的问题中遗漏了什么

我现在明白了。可能是A和B都有资格进行垃圾收集,并且它们之间存在引用。这应该没有问题,因为默认情况下,
finalize()
什么都不做。如果您为两个对象都编写自定义
finalize()
方法,那么您应该独立于它们的定稿顺序来编写代码。您还应该防止引用变成
null
,因为相应的对象可能已经被垃圾收集

是否有更好的替代方法来替代 检测和/或处理资源泄漏

我认为使用终结器时最重要的事情是检测和记录/警告泄漏,而不是处理泄漏。记录此泄漏的最佳时机是在垃圾收集资源对象之前。因此,终结器自然适合于此

我想强调一点:我不会使用终结器来处理忘记关闭资源的程序员,而是告诉他需要修复代码

在实现终结器时还需要注意哪些陷阱

对于具有终结器的对象,似乎也存在性能损失。你应该做一个测试看看你的表现如何。如果有一个重要的性能损失,我会尝试想象一种仅在开发时使用终结器记录资源泄漏的机制

并且按照Amir Raminfar的建议使用终结器继承对象时要小心


还有一件事:看看[
FileInputStream][1]
[FileOutputStream][2]
的源代码,它们使用终结器的原因相同。

我希望我的答案能有所帮助。如果我遗漏了什么,请告诉我。重新表述了关于从终结器访问可能已完成的对象的第二点。仍然很好奇这意味着什么。“如果你仍然可以访问它,它还没有最终确定。或者我在你的问题中遗漏了什么。”但是如果对象A引用了对象B,并且B在A之前最终确定,那么A不能从它的终结器访问B吗?编辑了我的帖子并重新表述了这个问题。所以当调用终结器时,引用垃圾收集对象的字段将
null
?偶数
final
字段?是的,偶数字段<代码>最终版指定引用一旦初始化就不会更改。