【问题标题】:Unload static fields卸载静态字段
【发布时间】:2012-01-02 00:24:51
【问题描述】:

我有一个使用复杂静态字段的 java 类,需要像 close() 这样的特殊操作,以便它们被 GC 安全清理。

对于静态字段的初始化,我使用static 块。但是我现在不知道如何安全卸载静态字段,以便在该字段被GC清理之前调用close()方法。

有没有办法卸载静态字段,类似于静态初始化块?

【问题讨论】:

  • 你考虑过使用 finalize() 吗?
  • 我有。但据我所知,finalize 适用于类的对象,而不是该类的静态字段。所以,finalize 对我来说不是一个选择。
  • 可能使用一个静态字段来保存对该类对象的活动引用数(在构造函数中增加,在 finalize() 中减少)并调用 close() 或您对这些对象拥有的任何清理方法当 finalize() 在递减后遇到引用计数为 0 时的“复杂”静态 - 不过我还没有尝试过。

标签: java static initialization


【解决方案1】:

没有。

静态类在您第一次使用时在运行时加载,仅在程序退出时卸载 (afaik)。

所以你可以在类本身中创建一个静态方法close 来清理静态成员,并在退出时调用它。

【讨论】:

  • 如果是网页应用,我怎么知道什么时候退出?
【解决方案2】:

您可以设置shutdown hook 来完成此操作,但您可能无法完成所有操作。您可能内存不足,或者进程可能在没有机会清理的情况下被杀死,等等。

最好确保您的数据一致性不依赖于此代码和/或将其移至在应用程序生命周期内定期清理的代码。

【讨论】:

  • ServletContextListener 比关闭 Web 应用程序的钩子更可取。见stackoverflow.com/questions/6950396/…
  • @Kublai,在 servlet 容器的上下文中,我同意,但是 OP 在她的问题中没有提到 web-app 上下文。
  • 她在对 Zom-B 的回答的评论中提到了这一点 - 同意这个问题应该提到这一点。
【解决方案3】:

没有办法按照您的要求进行操作,因为在加载类时会初始化静态块,并且 finalize() 仅适用于对象。

考虑将静态变量和其中的复杂操作替换为 Singleton 类及其实例。

这样,您可以使用finalize() 方法来执行您的close() 操作。

【讨论】:

  • finalize 现在已弃用。如果您需要清理非内存资源,则必须执行关闭挂钩、servlet 上下文侦听器或您的平台支持的其他关闭机制。
【解决方案4】:

在网络应用中,您可以使用ServletContextListener

【讨论】:

  • +1 这是要走的路,IMO。 contextDestroyed() 在取消部署时只调用一次。如有必要,contextInitialized() 也可用于在部署时显式初始化这些静态字段,而不是等待加载它们的特定类。
【解决方案5】:
private static Uninit cleanup = new Uninit();
....
private static class Uninit { 
    public Uninit() {} 

    public void finalize() {

                     //whatever you need done

    }
}

【讨论】:

  • 如果您想避免实现单例,这似乎是一个巧妙的技巧。您甚至可以使用私有匿名类。这有什么缺点吗?
  • 这只有在终结器真正被调用时才有效。
  • 到底为什么要公开 Uninit 构造函数? (使用 finalize(),显然你别无选择)
  • 就像 Archimedes Trajano 所说,终结器是不安全的,因为它没有被 GC 一致地调用。我在创建 OpenGL 程序时犯了这个错误,不得不重新开始工作。只需在您的主循环(或您的应用程序使用的任何地方)之后调用 close() 方法来清理
猜你喜欢
  • 1970-01-01
  • 2023-03-26
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2021-03-03
  • 1970-01-01
  • 2017-09-10
相关资源
最近更新 更多