【问题标题】:Good uses of the finalize() method [duplicate]finalize() 方法的良好用途[重复]
【发布时间】:2011-05-12 00:50:18
【问题描述】:

这主要是出于好奇。

除了调试/日志记录/分析目的之外,是否有人遇到过 Object.finalize() 的任何好的用法?

如果你还没有遇到过,你会说什么是好的用法?

【问题讨论】:

  • 您可以将其用作门挡或船锚:-)
  • :D 你的意思是它够重还是它不会漂浮?

标签: java finalizer object-destruction


【解决方案1】:

如果您的 Java 对象使用 JNI 来指示本机代码分配本机内存,则需要使用 finalize 以确保它被释放。

【讨论】:

  • 有人不同意这个吗?
  • 为什么不能像处理所有其他资源(打开的文件、数据库连接)一样只处理本机内存并要求显式关闭?您的 Java 对象可能只有一个 dispose()close() 来进行清理。
  • 这些东西通常都有终结器。 'close()' 允许您更快地释放资源,但 JVM 仍然使用终结器来保证它们最终会被释放。
  • @sleske:我们为什么不这样处理所有对象?显然,因为我们不必这样做。其他资源稀缺,所以我们必须close他们,但是一些本机内存可能没有问题,所以我们可以用Java的方式处理。
  • @maaartinus 你是说使用finalize() 是“Java 方式”,而不是使用“尝试资源”或手动调用close()
【解决方案2】:

在这里聚会迟到了,但我想我还是会插话的:

我发现终结器的最佳用途之一是调用显式终止方法,无论出于何种原因,这些方法都没有被调用。发生这种情况时,我们也会记录问题,因为它是一个 BUG!

因为:

  • 不保证终结器会根据语言规范迅速执行(或在技术上完全执行)
  • 执行很大程度上取决于 JVM 实现
  • 如果 GC 的线程优先级较低,有时会延迟执行

这只会留下他们可以在没有太大风险的情况下解决的少数任务。

【讨论】:

    【解决方案3】:
    1. 关闭外部连接(数据库、套接字等)
    2. 关闭打开的文件。甚至可能会尝试写一些额外的信息。
    3. 日志记录
    4. 如果此类运行的外部进程应该只在对象存在时才存在,您可以尝试在此处终止它们。

    但这只是一个后备,使用的是“正常”机制并没有工作。正常机制应显式启动。

    【讨论】:

    • 仅用作防止错误代码的保护非常重要。操作系统限制每个进程打开文件的数量,您可能会在调用 finalize() 之前很久就用完文件句柄。
    • 在完成时关闭打开的文件?由于在应用程序生命周期内可能永远不会调用 finalize 你确定这是一个好主意吗?我会说你需要在 finally 块中关闭打开的文件(或者你确定执行的东西)。
    • @Simeon 我认为 AlexR 的意思是这些是后备(就像他在回答中说的那样),以防由于某种原因文件没有在应该关闭的时候关闭,而不是你避免关闭文件并让终结器一直处理它。
    • 同意,即使它们是后备,但是如果您在 finalize 方法中关闭文件,您的文件可能会在应该关闭之前关闭,因为现在有方法可以预测(而且您不应该)何时垃圾收集将运行。
    • @Simeon 你的代码是如何工作的?引用的对象无法最终确定,因此您的连接对象在收集时已经无法访问。所以你不能用任何一种方式。一个对象的终结器关闭共享连接可能是一个缺陷,但这将是您的代码的一个错误。
    【解决方案4】:

    释放正常情况下应该手动释放,但由于某种原因没有释放的资源。可能会在日志中写入警告。

    【讨论】:

    • 哦,写日志是个好主意。然后,您不仅可以发布该内容,还可以收到有关该问题的一些警告。我从来没想过这点。我有一门课,我应该把它改成......
    【解决方案5】:

    在使用软引用缓存数据库支持的对象时,我使用它将数据写回数据库。

    【讨论】:

    • 你应该让一些图书馆来处理这些事情。
    【解决方案6】:

    我发现 finalize() 有一个很好的用途:释放大量可用且非独占的资源。

    例如,默认情况下,Linux 进程有 1024 个文件句柄可用,Windows 大约有 10000 个。这差不多,所以对于大多数应用程序,如果你打开一个文件,你不必调用 .close() (并使用丑陋的 try...finally 块),你会没事的 - finally() 会一段时间后为您免费。但是对于某些代码片段(如密集的服务器应用程序),必须使用 .close() 释放资源,否则 finally() 可能调用得太晚,您可能会用完文件句柄。

    Swing 使用相同的技术 - 用于显示窗口和绘图的操作系统资源不会由任何 .close() 方法释放,而只是由 finalize() 释放,因此您不必担心所有 .close () 或 .dispose() 方法,例如 SWT 中的方法。

    但是,当资源数量非常有限,或者您必须“锁定”资源才能使用它时,也要记得“解锁”它。例如,如果您在文件上创建文件锁,请记住还要删除此锁,否则其他人将无法读取或写入此文件,这可能导致死锁 - 然后您不能依赖 finalize() 删除这个锁是给你的——你必须在正确的地方手动操作。

    【讨论】:

    • -1:当调用close() 如此容易时,应用程序依赖终结器关闭文件句柄是无礼的高度。
    • 调用 .close() 一点也不容易:100% 正确的 close 处理需要两个 try... 子句(一个 try...finally 调用 close(),然后 close () 调用应该包含在 try...catch 中,然后应该记录错误以防止丢失原始异常),您正在处理的文件越多,情况就越糟糕,例如同时处理两个文件需要 4 个 try...catch 块 - 现在将这与使用脚本语言(例如 Perl)处理文件的便利性进行比较真是一团糟 - 你不必在所有地方都调用 close() !
    • 这是根本错误的。当调用dispose() 并且 调用dispose() 时释放与AWT/Swing 窗口关联的本机资源。只要一个窗口没有被显式释放,它就可以通过Window.getWindows() 访问,并且不会被垃圾回收。所以它的finalize() 方法不会被调用,即使它有一个终结器。此外,FileDescriptor 的终结器将关闭句柄,但不会刷新任何缓冲区。因此,不关闭文件相关资源可能会导致数据丢失。
    猜你喜欢
    • 1970-01-01
    • 2011-07-07
    • 2018-12-03
    • 2019-04-10
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2011-11-14
    • 1970-01-01
    相关资源
    最近更新 更多