【问题标题】:How to tell when a Java object's memory is released?如何判断 Java 对象的内存何时释放?
【发布时间】:2010-08-11 17:14:58
【问题描述】:

我有一个带有错误的 Swing 浏览器应用程序,当我在 GUI 中添加/删除时,没有为这些对象释放内存,我正在尝试追踪它们的存在。问题是我不知道如何判断某些东西何时真正从内存中完全释放。

有没有办法判断一个对象是否已从内存中释放?我已经习惯了 Objective-C,有几种方法可以告诉我。

谢谢

【问题讨论】:

  • (FWIW,它通常是一个监听器。)
  • 我认为可能是,但我试图删除所有 actionListeners 和 componentListeners

标签: java memory


【解决方案1】:

你不能在 Java 中真正做到这一点。所有提到终结器的答案都不是你想要的。

您能做的最好的事情就是将 PhantomReference 加入到 ReferenceQueue 中并轮询,直到获得引用为止。

final ReferenceQueue rq = new ReferenceQueue();
final PhantomReference phantom = new PhantomReference( referenceToObjectYouWantToTrack, rq );

您想在这里阅读 Peter Kofler 的回答(它解释了 PhantomReference 是什么):

Have you ever used Phantom reference in any project?

在这里阅读非常有趣:

http://www.kdgregory.com/index.php?page=java.refobj

基本上,我在一个项目中使用 PhantomReference,在该项目中,需要在安装软件时计算一次非常特殊的缓存。为了有效地计算这个(基于磁盘的)缓存,需要大量的内存(越多越好)。当释放大量内存时,我正在使用 PhantomReference 来“几乎准确地”跟踪。

【讨论】:

  • 很好的信息和链接,看起来彼得建议使用分析器。
  • 由于终结器可以解决 PhantomReferences 无法解决的问题,因此我更新了我的答案。我确实认为终结器对于 OP 正在尝试做的事情“足够好”,但我意识到我不应该鼓励半弃用的技术。
  • 到目前为止,我尝试的分析器没有分辨率来显示单个对象是否被释放。看起来这个答案(PhantomReferences)可能是最好的工具,但我很难找到一个如何使用它来仅跟踪已发布对象的示例。 kdgregory 的示例使用它来跟踪 SQL 连接。我到底在轮询什么 null 值、referenceQueue 或其他一些跟踪列表?
【解决方案2】:

有多种检测内存泄漏的方法。这是我目前正在考虑的三个:

  1. 将 Profiler 附加到您的应用程序(NetbeansEclipse TPTP 在这里应该很有用)
  2. 进行堆转储并分析(使用Eclipse Memory Analyzer)某个类的哪些实例由哪些其他实例保存在内存中。
  3. 附加VisualVM 以跟踪垃圾收集状态。

【讨论】:

  • 但问题没有提到任何内存泄漏。 OP 只想跟踪对象何时被 GC。
  • 不幸的是,#1 从来没有为我的小程序工作过,从来不知道为什么。我也会检查 VisualVM,目前正在尝试 YourKit。
  • @NoozNooz42 你是对的。但我认为你通常只在有内存问题时才寻找收集的东西。
【解决方案3】:

编辑:

正如 NoozNooz42 所指出的,PhantomReference 可以完成终结器所能做的一切,而不会出现终结器的问题。所以,我鼓励使用PhantomReferences 来扩展finalize()。我保留了我原来的帖子,因为我认为 Java 程序员至少应该知道finalize() 的存在。

原帖:

每个 Java 类都有一个 finalize() 方法,当没有其他对象持有对该类的引用时,该方法就会运行。你可以像这样扩展这个方法:

protected void finalize() throws Throwable {
    try {
        // Do whatever you want
    } finally {
        super.finalize();
    }
}

通过这样做,您可以确定是否有任何内容包含对相关对象的引用。如果您使用这种方法,请确保您始终致电 super.finalize()

最终确定参考:

http://java.sun.com/developer/technicalArticles/javase/finalization/

【讨论】:

  • 在 Java 中应该避免使用终结器,因为它们不能保证对象何时被真正收集。此外,finalize 仅在实例符合收集条件时才有效。通常有问题的对象由其他实例保存在内存中,因此最终确定无济于事。也可以在这里查看:my.safaribooksonline.com/0201310058/ch02lev1sec6(Josh Bloch 的 Effective Java)
  • @jwachter:很好,但您的链接需要登录才能阅读。
  • @Justin Ardini:最终确定发生在 WAY BEFORE 对象被 GC 处理之前。看我的回答:OP 在 PhantomReference 之后,而不是终结器。
  • 乍一看听起来 finalize() 类似于 obj-c 中的 dealloc() 但现在我不确定。垃圾收集是否调用了 finalize(),即在 finalize() 中放入 System.out.println("finalized") 是否表明正在收集对象?
  • 谢谢贾斯汀,澄清了它,不一样。
【解决方案4】:

试试YourKit。它是一个 Java 分析器,可以显示您的内存使用情况以及到底发生了什么。 IIRC,免费试用版可以与 Eclipse 集成,并具有付费版的所有功能(只是有时间限制)。

【讨论】:

    猜你喜欢
    • 2013-08-20
    • 1970-01-01
    • 2014-12-30
    • 2017-10-04
    • 2023-03-29
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2010-12-26
    相关资源
    最近更新 更多