如何调试 Java OutOfMemory 异常?

发布于 2024-10-09 07:07:45 字数 261 浏览 8 评论 0原文

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

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


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

What is the best way to debug java.lang.OutOfMemoryError exceptions?

When this happens to our application, our app server (Weblogic) generates a heap dump file. Should we use the heap dump file? Should we generate a Java thread dump? What exactly is the difference?


Update: What is the best way to generate thread dumps? Is kill -3 (our app runs on Solaris) the best way to kill the app and generate a thread dump? Is there a way to generate the thread dump but not kill the app?

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(8

淡看悲欢离合 2024-10-16 07:07:45

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

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

步骤 1. 在运行时启用堆

转储 使用 -XX:+HeapDumpOnOutOfMemoryError -XX:HeapDumpPath=/tmp 运行进程

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

步骤 2. 重现错误

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

JVM会自动编写一个类似java_pid12345.hprof的文件。

步骤 3. 获取转储 将

java_pid12345.hprof 复制到您的 PC(它至少与最大堆大小一样大,因此可能会变得相当大 - 如果需要,可以对其进行 gzip)。

步骤 4. 使用 IBM 的 堆分析器 或 Eclipse 的 内存分析器

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

IBM HeapAnalyzer

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

java -Xmx10g -jar ha456.jar

步骤 5. 识别堆使用量最大的区域

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

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

步骤 6. 修复代码

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

Analyzing and fixing out-of-memory errors in Java is very simple.

In Java the objects that occupy memory are all linked to some other objects, forming a giant tree. The idea is to find the largest branches of the tree, which will usually point to a memory leak situation (in Java, you leak memory not when you forget to delete an object, but when you forget to forget the object, i.e. you keep a reference to it somewhere).

Step 1. Enable heap dumps at run time

Run your process with -XX:+HeapDumpOnOutOfMemoryError -XX:HeapDumpPath=/tmp

(It is safe to have these options always enabled. Adjust the path as needed, it must be writable by the java user)

Step 2. Reproduce the error

Let the application run until the OutOfMemoryError occurs.

The JVM will automatically write a file like java_pid12345.hprof.

Step 3. Fetch the dump

Copy java_pid12345.hprof to your PC (it will be at least as big as your maximum heap size, so can get quite big - gzip it if necessary).

Step 4. Open the dump file with IBM's Heap Analyzer or Eclipse's Memory Analyzer

The Heap Analyzer will present you with a tree of all objects that were alive at the time of the error.
Chances are it will point you directly at the problem when it opens.

IBM HeapAnalyzer

Note: give HeapAnalyzer enough memory, since it needs to load your entire dump!

java -Xmx10g -jar ha456.jar

Step 5. Identify areas of largest heap use

Browse through the tree of objects and identify objects that are kept around unnecessarily.

Note it can also happen that all of the objects are necessary, which would mean you need a larger heap. Size and tune the heap appropriately.

Step 6. Fix your code

Make sure to only keep objects around that you actually need. Remove items from collections in a timely manner. Make sure to not keep references to objects that are no longer needed, only then can they be garbage-collected.

红ご颜醉 2024-10-16 07:07:45

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

I've had success using a combination of Eclipse Memory Analyzer (MAT) and Java Visual VM to analyze heap dumps. MAT has some reports that you can run that give you a general idea of where to focus your efforts within your code. VisualVM has a better interface (in my opinion) for actually inspecting the contents of the various objects that you are interested in examining. It has a filter where you can have it display all instances of a particular class and see where they are referenced and what they reference themselves. It has been a while since I've used either tool for this they may have a closer feature set now. At the time using both worked well for me.

沒落の蓅哖 2024-10-16 07:07:45

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

OutOfMemoryError 描述了消息描述中的错误类型。您必须检查错误消息的描述来处理异常。

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

java.lang.OutOfMemoryError: Java heap space:

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

java.lang.OutOfMemoryError:超出 GC 开销限制

原因:详细信息“GC Overhead Limit Excessed”表示垃圾收集器一直在运行,Java 程序进展非常缓慢

java.lang.OutOfMemoryError: Requested array size超出VM限制:

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

java.lang.OutOfMemoryError:元空间

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

java.lang.OutOfMemoryError:出于原因请求大小字节。交换空间不足?

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

java.lang.OutOfMemoryError:压缩类空间

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

如果使用UseCompressedClassPointers,则可用于类元数据的空间量固定为CompressedClassSpaceSize。如果 UseCompressedClassPointers 所需的空间超过 CompressedClassSpaceSize,则会引发 java.lang.OutOfMemoryError,并详细说明压缩类空间。

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

是的。您可以使用此堆堆转储文件来使用 visualvmmat
您可以使用线程转储来进一步了解线程的状态。

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

kill -3 生成线程转储,并且此命令不会杀死 java 进程。

What is the best way to debug java.lang.OutOfMemoryError exceptions?

The OutOfMemoryError describes type of error in the message description. You have to check the description of the error message to handle the exception.

There are various root causes for out of memory exceptions. Refer to Oracle documentation page for more details.

java.lang.OutOfMemoryError: Java heap space:

Cause: The detail message Java heap space indicates object could not be allocated in the Java heap.

java.lang.OutOfMemoryError: GC Overhead limit exceeded:

Cause: The detail message "GC overhead limit exceeded" indicates that the garbage collector is running all the time and Java program is making very slow progress

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

Cause: The detail message "Requested array size exceeds VM limit" indicates that the application (or APIs used by that application) attempted to allocate an array that is larger than the heap size.

java.lang.OutOfMemoryError: Metaspace:

Cause: Java class metadata (the virtual machines internal presentation of Java class) is allocated in native memory (referred to here as metaspace)

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

Cause: The detail message "request size bytes for reason. Out of swap space?" appears to be an OutOfMemoryError exception. However, the Java HotSpot VM code reports this apparent exception when an allocation from the native heap failed and the native heap might be close to exhaustion

java.lang.OutOfMemoryError: Compressed class space

Cause: On 64-bit platforms a pointer to class metadata can be represented by a 32-bit offset (with UseCompressedOops). This is controlled by the command line flag UseCompressedClassPointers (on by default).

If the UseCompressedClassPointers is used, the amount of space available for class metadata is fixed at the amount CompressedClassSpaceSize. If the space needed for UseCompressedClassPointers exceeds CompressedClassSpaceSize, a java.lang.OutOfMemoryError with detail Compressed class space is thrown.

Should we use the heap dump file? Should we generate a Java thread dump? What exactly is the difference?

Yes. You can use this heap heap dump file to debug the issue using profiling tools like visualvm or mat
You can use Thread dump to get further insight about status of threads.

What is the best way to generate thread dumps? Is kill -3 (our app runs on Solaris) the best way to kill the app and generate a thread dump? Is there a way to generate the thread dump but not kill the app?

kill -3 <process_id> generates Thread dump and this command does not kill java process.

梦初启 2024-10-16 07:07:45

调试 OutOfMemoryError 问题通常非常困难。我建议使用分析工具。 JProfiler 工作得很好。我过去使用过它,它非常有帮助,但我确信还有其他的至少同样好。

回答您的具体问题:

堆转储是整个堆的完整视图,即使用 new 创建的所有对象。如果您的内存不足,那么这将相当大。它显示您拥有的每种类型对象的数量。

线程转储显示每个线程的堆栈,显示转储时每个线程在代码中的位置。请记住,任何线程都可能导致 JVM 内存不足,但实际引发错误的可能是不同的线程。例如,线程 1 分配一个字节数组,该数组填满了所有可用的堆空间,然后线程 2 尝试分配一个 1 字节数组并抛出错误。

It is generally very difficult to debug OutOfMemoryError problems. I'd recommend using a profiling tool. JProfiler works pretty well. I've used it in the past and it can be very helpful, but I'm sure there are others that are at least as good.

To answer your specific questions:

A heap dump is a complete view of the entire heap, i.e. all objects that have been created with new. If you're running out of memory then this will be rather large. It shows you how many of each type of object you have.

A thread dump shows you the stack for each thread, showing you where in the code each thread is at the time of the dump. Remember that any thread could have caused the JVM to run out of memory but it could be a different thread that actually throws the error. For example, thread 1 allocates a byte array that fills up all available heap space, then thread 2 tries to allocate a 1-byte array and throws an error.

夏九 2024-10-16 07:07:45

您还可以使用 jmap/jhat 附加到正在运行的 Java 进程。如果您必须调试实时运行的应用程序,这些(系列)工具非常有用。

您还可以将 jmap 作为 cron 任务运行,登录到稍后可以分析的文件(我们发现这对于调试实时内存泄漏很有用)

jmap -histo:live <pid> | head -n <top N things to look for> > <output.log>

Jmap 还可以用于使用 -dump 选项生成堆转储可以通过 jhat 来阅读。

请参阅以下链接了解更多详情
http://www.lshift .net/blog/2006/03/08/java-memory-profiling-with-jmap-and-jhat

这是另一个书签链接
http://java.sun.com/developer/technicalArticles/J2SE/monitoring/

You can also use jmap/jhat to attach to a running Java process. These (family of) tools are really useful if you have to debug a live running application.

You can also leave jmap running as a cron task logging into a file which you can analyse later (It is something which we have found useful to debug a live memory leak)

jmap -histo:live <pid> | head -n <top N things to look for> > <output.log>

Jmap can also be used to generate a heap dump using the -dump option which can be read through the jhat.

See the following link for more details
http://www.lshift.net/blog/2006/03/08/java-memory-profiling-with-jmap-and-jhat

Here is another link to bookmark
http://java.sun.com/developer/technicalArticles/J2SE/monitoring/

没︽人懂的悲伤 2024-10-16 07:07:45

看起来 IBM 提供了一个用于分析这些堆转储的工具:http://www.alphaworks.ibm。 com/tech/heaproots;更多信息请访问 http://www-01.ibm.com/support/docview .wss?uid=swg21190476

It looks like IBM provides a tool for analyzing those heap dumps: http://www.alphaworks.ibm.com/tech/heaproots ; more at http://www-01.ibm.com/support/docview.wss?uid=swg21190476 .

假情假意假温柔 2024-10-16 07:07:45

一旦您获得了查看堆转储的工具,请查看线程堆栈中处于运行状态的任何线程。它可能是出现错误的人之一。有时,堆转储会告诉您哪个线程在顶部出现错误。

这应该为您指明正确的方向。然后采用标准调试技术(日志记录、调试器等)来解决问题。使用 Runtime 类获取当前内存使用情况,并在相关方法或进程执行时将其记录下来。

Once you get a tool to look at the heap dump, look at any thread that was in the Running state in the thread stack. Its probably one of those that got the error. Sometimes the heap dump will tell you what thread had the error right at the top.

That should point you in the right direction. Then employ standard debugging techniques (logging, debugger, etc) to hone in on the problem. Use the Runtime class to get the current memory usage and log it as the method in or process in question executes.

‘画卷フ 2024-10-16 07:07:45

我一般使用Eclipse内存分析器。它显示可疑的罪魁祸首(占用大部分堆转储的对象)以及生成这些对象的不同调用层次结构。一旦映射存在,我们就可以返回代码并尝试了解代码路径中的任何位置是否存在任何可能的内存泄漏。

然而,OOM并不总是意味着存在内存泄漏。应用程序在稳定状态或负载下所需的内存始终有可能在硬件/VM 中不可用。例如,可能有一个 32 位 Java 进程(使用的最大内存约为 4GB),而 VM 只有 3 GB。在这种情况下,应用程序最初可能运行良好,但当内存需求接近 3GB 时,可能会遇到 OOM。

正如其他人提到的,捕获线程转储的成本并不高,但捕获堆转储的成本却很高。我观察到,在捕获堆转储应用程序时(通常)会冻结,只有杀死然后重新启动才能帮助恢复。

I generally use Eclipse Memory Analyzer. It displays the suspected culprits (the objects which are occupying most of the heap dump) and different call hierarchies which is generating those objects. Once that mapping is there we can go back to the code and try to understand if there is any possible memory leak any where in the code path.

However, OOM doesn't always mean that there is a memory leak. It's always possible that the memory needed by an application during the stable state or under load is not available in the hardware/VM. For example, there could be a 32 bit Java process (max memory used ~ 4GB) where as the VM has just 3 GB. In such a case, initially the application may run fine, but OOM may be encountered as and when the memory requirement approaches 3GB.

As mentioned by others, capturing thread dump is not costly, but capturing heap dump is. I have observed that while capturing heap dump application (generally) freezes and only a kill followed by restart helps to recover.

~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文