简体   繁体   English

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

[英]How to debug memory leak where exception instances in heap dump have no inbound references?

I've been trying to diagnose a memory leak in an Android application I'm writing. 我一直在尝试诊断我正在编写的Android应用程序中的内存泄漏。 I got a heap dump loaded into Eclipse, but the results I'm seeing are very curious. 我有一个堆转储加载到Eclipse中,但我看到的结果非常好奇。 There are some 20,000 instances of an exception (specifically, LDAPException from the UnboundID LDAP library) in the heap with no inbound references. 堆中有大约20,000个异常实例(特别是来自UnboundID LDAP库的LDAPException),没有入站引用。

That is, they show up at the root of the dominator tree. 也就是说,它们出现在支配者树的根部。 The OQL SELECT objects e FROM com.unboundid.ldap.sdk.LDAPException e WHERE (inbounds(e).length = 0) returns over 20,000 results, totalling to nearly all of the heap. OQL SELECT objects e FROM com.unboundid.ldap.sdk.LDAPException e WHERE (inbounds(e).length = 0)返回超过20,000个结果,总计几乎所有堆。 And yet, the GC runs before the heap dump and I can see that it's running in the console, repeatedly, during the execution of the leaky code. 然而,GC在堆转储之前运行,我可以看到它在执行泄漏代码期间反复运行在控制台中。 If these instances have no inbound refs, what could be keeping them alive? 如果这些实例没有入站参考,那么可以让它们保持活力?

I also tried doing a "shortest paths to GC" query. 我也尝试过“最短的GC路径”查询。 It shows one LDAPConnectionReader row retaining 2 instances, and ~20k LDAPException @ <addr> unknown rows with various hex addresses. 它显示了一个保留2个实例的LDAPConnectionReader行,以及具有各种十六进制地址的~20k LDAPException @ <addr> unknown行。

Update : I haven't had time to further diagnose this since posting it, and the bounty I posted is ending before I likely will. 更新 :自发布以来我没有时间进一步诊断这个问题,我发布的奖金在我可能会结束之前结束。 I'm awarding it as best I can now, lest the points go to waste. 我现在尽可能地奖励它,以免浪费点数。 Thanks to everyone who looked into this! 感谢所有关注此事的人! I will come back later and update again with the results of further diagnosis, when life is a little less hectic. 我将稍后回来并再次更新进一步诊断的结果,当生活稍微忙碌时。

Whether or not these Exceptions are being thrown, in terms of memory usage, that detail is pretty much irrelevant. 无论这些异常是否被抛出,就内存使用而言,这个细节都是无关紧要的。

While you'd like to see in the heap dump who holds the references, for some reason, you're not able to get to this. 虽然您希望在堆转储中看到谁拥有引用,但由于某种原因,您无法实现此目的。 I wonder if native code would get symbolized properly in the heap dump tool? 我想知道本机代码是否会在堆转储工具中得到正确的符号化?

Either way, as something new to try, I'd suggest not debugging the point at which these Exceptions are thrown but where they are created . 无论哪种方式,作为尝试的新事物,我建议不要调试抛出这些异常但创建它们的位置。 Put breakpoints on the class and/or all of its constructors. 在类和/或其所有构造函数上放置断点。 Ideally, you'd just get this information from the heap dump references, but it still may prove to be informative if you can see who is repeatedly constructing these objects... I'm guessing they come from the same place. 理想情况下,您只是从堆转储引用中获取此信息,但如果您可以看到谁重复构建这些对象,它仍然可以证明是有用的......我猜它们来自同一个地方。

If you are using Eclipse, you can add a breakpoint on the LDAPException . 如果您使用的是Eclipse,则可以在LDAPException上添加断点。 Here you can find a tutorial on how to set one: Eclipse Tip: Breakpoint on Exception . 在这里,您可以找到有关如何设置一个的教程: Eclipse提示:异常断点

These breakpoints pause the execution whenever an exception of the selected type is thrown. 只要抛出所选类型的异常,这些断点就会暂停执行。 Once you find out the conditions that throw so much exceptions, you can fix the bug. 一旦找到引发如此多异常的条件,就可以修复bug。

It's not exactly debugging why unreferenced Exceptions are filling the heap, but I hope it can help. 它并没有完全调试为什么未引用的异常填满堆,但我希望它可以帮助。

I'm not familiar with OQL, or the Android platform in particular, or the inner workings of Java GC on that platform, but most obvious to me is the missing LDAPException metadata. 我不熟悉OQL,特别是Android平台,或者该平台上Java GC的内部工作原理,但对我来说最明显的是缺少的LDAPException元数据。 It's got error codes, messages, methods, etc... where is it? 它有错误代码,消息,方法等......它在哪里? was it uninitialized? 这是未初始化的吗? are you prevented from posting all that stuff? 你有没有发布所有这些东西? Something like a server redirecting to itself might make me say "oh, that's weird, but it kinda made sense." 像服务器重定向到自身的东西可能让我说“哦,这很奇怪,但它有点意义。”

Have you tried swapping this lib for the JDK one ? 您是否尝试过将此lib替换为JDK Looks like that should be easy if it's possible. 看起来如果可能的话应该很容易。

Then I would start squeezing the heap for everything it's got. 然后我会开始挤压它所有的东西。 GC characteristics could provide clues. GC特征可以提供线索。 Are there instances that escape collection somehow? 是否存在以某种方式逃避收集的实例? How many are created per second? 每秒创建多少? What fraction of stale ones are gc'd each pass, or is it a constant amount? 每次通过gc'd会有多少陈旧的,或者它是不变的? Are they being created in a busy loop like Danny was talking about? 他们是在像Danny谈论的忙碌循环中创建的吗? What if you call System.gc() in a busy loop? 如果你在繁忙的循环中调用System.gc()怎么办?

But yeah, that's where I start print debugging. 但是,是的,我开始打印调试。 Hopefully there's a better solution. 希望有更好的解决方案。 :-P :-P

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM