如何调试 Java OutOfMemory 异常?

调试异常的最佳方法是什么?java.lang.OutOfMemoryError

当应用程序发生这种情况时,我们的应用程序服务器 (Weblogic) 会生成一个堆转储文件。我们应该使用堆转储文件吗?我们应该生成一个Java线程转储吗?究竟有什么区别?


更新:生成线程转储的最佳方法是什么?(我们的应用程序在 Solaris 上运行)是终止应用程序并生成线程转储的最佳方式吗?有没有办法生成线程转储但不终止应用程序?kill -3


答案 1

在Java中分析和修复内存不足的错误非常简单。

在Java中,占用内存的对象都链接到其他一些对象,形成一棵巨树。这个想法是找到树的最大分支,这通常指向内存泄漏情况(在Java中,你泄漏内存不是当你忘记删除一个对象,而是当你忘记忘记忘记对象时,即你在某个地方保留对它的引用)。

步骤 1.在运行时启用堆转储

使用 以下命令运行您的流程-XX:+HeapDumpOnOutOfMemoryError -XX:HeapDumpPath=/tmp

(始终启用这些选项是安全的。根据需要调整路径,它必须可由java用户写入)

步骤2.重现错误

让应用程序运行,直到发生。OutOfMemoryError

JVM 将自动写入一个类似 .java_pid12345.hprof

第3步.获取转储

复制到您的PC(它至少与您的最大堆大小一样大,因此可以变得相当大 - 如有必要,可以将其gzip)。java_pid12345.hprof

步骤 4.使用 IBM 的 Heap Analyzer 或 Eclipse 的 Memory Analyzer 打开转储文件

堆分析器将为您提供在发生错误时处于活动状态的所有对象的树。当它打开时,它可能会直接指向问题。

IBM HeapAnalyzer

注意:给HeapAnalyzer足够的内存,因为它需要加载整个转储!

java -Xmx10g -jar ha456.jar

第5步.确定堆使用量最大的区域

浏览对象树并识别不必要地保留在周围的对象。

请注意,所有对象都是必需的,这意味着您需要更大的堆。适当地调整堆的大小调整

第6步.修复代码

确保只保留您实际需要的对象。及时从集合中删除项目。确保不要保留对不再需要的对象的引用,只有这样才能对它们进行垃圾回收。


答案 2

我已经成功地使用Eclipse Memory Analyzer(MAT)Java Visual VM的组合来分析堆转储。MAT 有一些可以运行的报告,这些报告可以让您大致了解在代码中将精力集中在何处。VisualVM有一个更好的界面(在我看来),用于实际检查您有兴趣检查的各种对象的内容。它有一个过滤器,您可以在其中显示特定类的所有实例,并查看它们被引用的位置以及它们自己引用的内容。自从我使用任何一种工具以来,已经有一段时间了,它们现在可能具有更接近的功能集。当时使用两者都对我很好。


推荐