【问题标题】:why we override finalize() method in java? [duplicate]为什么我们在 java 中重写 finalize() 方法? [复制]
【发布时间】:2013-06-26 16:32:06
【问题描述】:

当我们不知道何时可能运行任何给定对象的 finalize() 方法时,我们需要在 java 中重写 finalize() 方法的地方?我们可以在 finalize() 中关闭什么类型的资源?什么是最好的GC什么时候会调用finalize()方法?

【问题讨论】:

  • 这是一道三合一题。答案可能是一本专着。
  • 我们不这样做是因为一旦您使用完资源就应该关闭它,而且我们无法确定何时会调用 finalize()。
  • 提供终结器的一个原因可能是识别代码中未正确关闭的对象(通过跟踪)。 IE。不是用于编程的工具,而是用于调试的工具。

标签: java


【解决方案1】:

首先,finalization 的目的是在对象被垃圾回收之前让无法访问的对象有机会执行任何清理操作。
例如,关闭一个打开的数据库连接。

应覆盖finailze() 方法,以便对象包含清理代码或在对象被垃圾回收之前处理应完成的系统资源。

关于GC调用finalize()方法的最佳时机是什么?,我们可以通过两种方式请求JVM执行垃圾回收:

  1. Runtime.getRuntime().gc();
  2. System.gc();

finalize()中我们可以关闭什么类型的资源,答案分两种情况:

  1. 将所有available对象引用设置为null的目的后 创建对象完成。

  2. 使引用变量引用另一个对象:将引用变量与对象解耦,并将其设置为引用另一个对象,因此在重新分配之前它所引用的对象符合 Grabage Collection 的条件。

【讨论】:

  • 关闭数据库连接我们也可以在finally块中执行?为什么我依赖finalize()方法。
  • @JaikantBhagwanDas: finally 块是在 try 或 try-catch 之后执行的,它是为特殊目的而创建的,但是 GC 不关心是否有 finally 块,它会当对象符合 Grabaged 条件时可用。
【解决方案2】:

当您的类具有不会被 GC 清理的资源(例如文件句柄或数据库连接)时,您应该覆盖 finalize。这些资源应该在应用程序代码中清理,因为正如您所说,我们不知道何时运行 finalize,但是最好也清理这些资源终结器,以防程序员搞砸并保持资源打开(如果在 finalize 运行时资源仍然打开,则将此记录为警告或错误,因为这意味着应用程序代码没有正确清理资源) .

.NET 如果程序员通过例如正确清理对象的资源,则可以抑制终结器。调用dispose,但不幸的是我不认为Java 允许类似的模式。

【讨论】:

  • 我们也可以在 finally 块中做同样的事情。那么为什么在 finalize() 方法中这样做。任何适合的真实上下文?
  • @Jaikant Bhagwan Das 问题是程序员可能忘记清理finally 块中的资源。对于被覆盖的finalize 方法,我最常看到的模式是检查对象的资源是否仍然打开 - 如果它们是打开的,则关闭它们,并将其记录为错误,因为这意味着在某处程序资源没有被正确清理。然后,当程序发布到生产环境时,如果它导致性能问题,有时会注释掉终结器。
  • 实现finalize 确实不是一个好主意,除非,正如您所指出的,用于调试。如果有资源泄漏,必须将其移除,而不是留给finalize 处理。
  • @MarkoTopolnik 在修复之前,finalize() 可以避免系统在生产中崩溃。当然,您应该将一些高严重性的日志放入其中。这对于确定性行为而言较少,但对于良好的旧双重安全性而言更多。
【解决方案3】:

最好在您手动调用的关闭方法中关闭资源。 finalize 仅在对象被垃圾回收时才被调用,这可能要等到您使用完对象很久之后才会调用。

我曾经覆盖 finalize 的唯一原因是在我的应用程序中调试内存使用情况,其中一些对象没有被收集。

【讨论】:

    【解决方案4】:

    来自我的笔记:

    在对象被垃圾回收之前调用名为 finalize() 的方法。不需要释放任何对象,但可能需要释放一些其他资源(例如打开的文件描述符)。

    protected void finalize() {
        if( fd != null ) {
            try {
                closeIt() ;
            } catch (IOException e) {
                // print an error something, or otherwise try to recover
            }
        }
    }
    

    理论上,终结器可能会做一些事情来防止对象被垃圾收集(例如,将“this”存储在某个引用中)。这绝不是一件有用的事情。

    与构造函数不同,终结器不会自动链接。手动链接它们是一个非常好的主意,最好是在终结器的末尾:

    protected void finalize() {
        // free resources consumed by this class
        // chain upward:
        super.finalize() ;
    }
    

    在大多数情况下,您几乎不需要编写 finalizer()。


    编辑:此答案的早期版本将 finalize() 声明为抛出 IOException。回想起来,这可能是一个非常糟糕的主意。我不知道我在想什么。

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 2016-12-28
      • 1970-01-01
      • 2011-07-07
      • 1970-01-01
      • 2019-04-10
      • 2018-12-03
      • 2021-02-08
      相关资源
      最近更新 更多