代码之家  ›  专栏  ›  技术社区  ›  Walter Mundt

如果堆转储中的异常实例没有入站引用,如何调试内存泄漏?

  •  6
  • Walter Mundt  · 技术社区  · 14 年前

    我一直在尝试诊断我正在编写的Android应用程序中的内存泄漏。我在Eclipse中加载了一个堆转储,但是我看到的结果非常奇怪。堆中有大约20000个异常实例(特别是来自未绑定LDAP库的ldapException),没有入站引用。

    也就是说,它们出现在主宰树的根部。OQL SELECT objects e FROM com.unboundid.ldap.sdk.LDAPException e WHERE (inbounds(e).length = 0) 返回超过20000个结果,总计几乎所有堆。然而,GC在堆转储之前运行,我可以看到它在控制台中运行,在执行泄漏代码的过程中反复运行。如果这些实例没有入站引用,那么怎样才能使它们保持活动状态?

    我还尝试执行“最短的GC路径”查询。它显示一个保留2个实例的ldapConnectionReader行和~20k LDAPException @ <addr> unknown 具有各种十六进制地址的行。

    更新 :自从发布后,我还没有时间进一步诊断这个问题,而且我发布的奖金在我可能之前就结束了。我正在尽我所能地奖励它,以免浪费积分。感谢所有关注这件事的人!我稍后会回来,并再次更新进一步诊断的结果,当生活不那么紧张的时候。

    3 回复  |  直到 14 年前
        1
  •  4
  •   RonU xtoddx    14 年前

    不管这些异常是否被抛出,在内存使用方面,这个细节都是非常不相关的。

    虽然您希望在堆转储中看到谁持有引用,但出于某种原因,您无法做到这一点。我想知道本地代码是否可以在堆转储工具中正确地进行符号化?

    不管怎样,作为一种新的尝试,我建议不要调试这些异常的位置。 投掷 但是他们在哪里 创建 . 在类和/或其所有构造函数上放置断点。理想情况下,您只需要从堆转储引用中获取这些信息,但是如果您能够看到谁在重复构造这些对象,那么它仍然可以提供信息……我猜他们来自同一个地方。

        2
  •  1
  •   Tomas Narros    14 年前

    如果使用Eclipse,则可以在 LDAPException . 在这里,您可以找到关于如何设置一个的教程: Eclipse Tip: Breakpoint on Exception .

    每当抛出所选类型的异常时,这些断点暂停执行。 一旦发现抛出如此多异常的条件,就可以修复这个bug。

    不完全是调试未引用异常填充堆的原因,但我希望它能有所帮助。

        3
  •  1
  •   Robert Karl    14 年前

    我不熟悉OQL,特别是Android平台,或者在那个平台上的Java GC的内部操作,但是对我来说最明显的是缺失。 LDAPException 元数据。它有错误代码、消息、方法等。它在哪里?它是否未初始化?你不能把这些东西都发出去吗?某物 like a server redirecting to itself 可能会让我说“哦,这很奇怪,但这有点道理。”

    你试过把这个库换成 the JDK one ?如果可能的话,看起来应该很容易。

    然后我就开始压缩堆中的所有东西。GC特征可以提供线索。是否存在以某种方式转义集合的实例?每秒创建多少个?每次GC通过的陈旧的部分是多少,或者它是一个常量?他们是不是像丹尼所说的那样在一个繁忙的循环中被创造出来的?如果你打电话怎么办 System.gc() 在繁忙的循环中?

    但是的,这就是我开始打印调试的地方。希望有更好的解决方案。-P