如何调试Java OutOfMemory异常?

Mar*_*eon 13 java coredump out-of-memory thread-dump java1.4

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

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


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

rus*_*tyx 11

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

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

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

运行您的流程 -XX:+HeapDumpOnOutOfMemoryError -XX:HeapDumpPath=/tmp

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

步骤 2. 重现错误

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

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

步骤 3. 获取转储

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

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

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

IBM 堆分析器

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

java -Xmx10g -jar ha456.jar
Run Code Online (Sandbox Code Playgroud)

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

浏览对象树并识别不必要的对象。

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

步骤 6. 修复您的代码

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


laz*_*laz 7

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


Rav*_*abu 5

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

OutOfMemoryError描述在信息描述的错误的类型。您必须检查错误消息的描述才能处理异常。

内存不足异常有多种根本原因。有关更多详细信息,请参阅 oracle 文档页面

java.lang.OutOfMemoryError: Java heap space

原因:Java 堆空间的详细消息指示无法在 Java 堆中分配对象。

java.lang.OutOfMemoryError: GC Overhead limit exceeded

原因:详细信息“超出GC开销限制”表示垃圾收集器一直在运行,Java程序进展非常缓慢

java.lang.OutOfMemoryError: Requested array size exceeds VM limit

原因:详细消息“请求的数组大小超出 VM 限制”表明应用程序(或该应用程序使用的 API)尝试分配大于堆大小的数组。

java.lang.OutOfMemoryError: Metaspace

原因: Java 类元数据(Java 类的虚拟机内部表示)被分配在本机内存中(这里称为元空间)

java.lang.OutOfMemoryError: request size bytes for reason. Out of swap space?

原因:详细消息“出于原因请求大小字节。交换空间不足?” 似乎是个OutOfMemoryError例外。但是,当从本机堆分配失败并且本机堆可能接近耗尽时,Java HotSpot VM 代码会报告此明显异常

java.lang.OutOfMemoryError: Compressed class space

原因:在 64 位平台上,指向类元数据的指针可以用 32 位偏移量表示(使用 UseCompressedOops)。这由命令行标志 UseCompressedClassPointers 控制(默认情况下启用)。

如果UseCompressedClassPointers使用 ,则可用于类元数据的空间量固定为数量CompressedClassSpaceSize。如果需要的空间UseCompressedClassPointers超过CompressedClassSpaceSizejava.lang.OutOfMemoryError则会抛出一个带有详细信息的压缩类空间。

注意:有不止一种类元数据——类元数据和其他元数据。只有 klass 元数据存储在由 限定的空间中CompressedClassSpaceSize。其他元数据存储在 Metaspace 中。

我们应该使用堆转储文件吗?我们应该生成 Java 线程转储吗?究竟有什么区别?

是的。您可以使用此堆堆转储文件使用visualvmmat等分析工具调试问题 您可以使用线程转储进一步了解线程的状态。

请参阅此 SE 问题以了解不同之处:

Websphere中javacore、线程转储和堆转储的区别

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

kill -3 <process_id> 生成线程转储并且此命令不会终止 java 进程。