什么是 OutOfMemoryError 以及如何调试和修复它

Posted

技术标签:

【中文标题】什么是 OutOfMemoryError 以及如何调试和修复它【英文标题】:What is an OutOfMemoryError and how do I debug and fix it 【发布时间】:2014-08-22 00:12:47 【问题描述】:

我的 Java 程序抛出了 OutOfMemoryError。如何调试和解决此问题?


许多Java 新手都难以应付OutOfMemoryError。这是创建一个规范问题的尝试,该问题将回答有关OutOfMemoryError 的最常见问题。我正在创建这个新问题,而不是调整之前关于 OutOfMemoryError 的众多问题之一,因为这些问题及其答案与一个人的特定问题紧密相关。

这个问题与general advice on debugging exceptions不同,因为问题的原因并不总是在调用堆栈上,需要具体的建议。

【问题讨论】:

投反对票。有趣的。好像有些人不想创建规范问题。 我确定人们想要a 规范问题,而不是您的 规范问题。 :-P(我不是反对者之一。) 这个网站上已经有十几个关于如何在 Java 中处理 OutOfMemoryError 的问题。多加一个对任何人有什么帮助? @DavidWallace “规范”问题的目的是使所有其他类似问题标记为规范问题的重复。不过,我的意见是,为什么选择这个而不是其他任何一个? 它们几乎都是彼此的重复。再添加一个并不能解决任何问题。 【参考方案1】:

OutOfMemoryError 是 Java 虚拟机 (JVM) 抛出的异常,因为它需要为(新)对象分配内存,但该对象可用的内存不足。 JVM 将首先尝试通过running the garbage collector 释放死对象使用的内存。

由于OutOfMemoryErrorVirtualMachineError,JVM 被允许throw it at any time,尽管它必须try to release memory through garbage collection first。

但是,在实践中,它可能会从试图创建无法为其分配内存的对象的new 语句中抛出。因此,您应该首先检查与异常相关的堆栈跟踪,以获取有关问题原因as you would for any other exception 的线索。

如果尝试分配数组时抛出异常(例如int[] values = new int[n]),原因可能是您尝试创建过大的数组(n 太大)。你是不是在计算你需要的数组大小时出错了? 如果尝试在其他人编写的容器类的方法中分配数组而引发异常,原因可能是您的代码要求容器存储过多的内容。 ArrayList.reserve(int)HashMap(int) 等方法必须分配存储空间以备将来使用。您是否在计算所需容器的尺寸时出现错误? 如果异常是从循环内部抛出的,原因可能是代码循环了太多次。您的循环终止条件是否正确?如果是for 循环,您是否要求它循环正确的次数?

如果堆栈跟踪没有提供足够的线索,您可以尝试使用堆分析器。这是一个监控程序,使您能够在程序运行时检查对象使用的内存,或者检查程序退出时编写的堆转储。它可以提供有关存储在内存中的对象的大小、数量和类别的信息。

JVM 有一个可用的finite amount of memory。您可能会得出结论,您的程序运行正常,但只需要比可用内存更多的内存来运行。如果您没有明确告诉 JVM 使用多少内存,大多数实现将根据您的计算机拥有的 RAM 量选择 sensible default 数量,但该数量对于您的程序来说可能太小了。 JVM 的命令行选项可以控制有多少内存可用。对于大多数 JVM 实现,其中最重要的选项是 -Xmx-Xms

【讨论】:

“JVM”中的“the”是否不包括其他 JVM,例如 Dalvik,它们也可能抛出相同的 OutOfMemory 异常? @MehmetM.Inanc 不,JVM 不仅仅指 HotSpot。 过度递归导致***Error,而不是OutOfMemoryError 过度递归如果不首先导致OutOfMemoryError,则会导致***Error【参考方案2】:

要调试OutOfMemoryError,请使用-XX:+HeapDumpOnOutOfMemoryError 选项调用JVM,这将导致在OutOfMemoryError 发生时写出堆转储。然后使用VisualVM、jhat 或fasthat 之类的工具查看堆转储。

您还可以随时使用jmap 和-dump 选项手动生成堆转储。

披露:我是 fasthat 的维护者,它是 jhat 的一个分支。

【讨论】:

【参考方案3】:

当应用程序资源用完JVM堆分配的内存时,抛出OutOfMemmoryException。尝试增加 JVM 堆大小。

【讨论】:

@BigMike 这些案例实际上也是堆的一部分。 :-) @ChrisJester-Young:我遇到过一次与 GC 相关的问题,它与堆的数量没有严格的关系,而仅与其中的小对象的数量有关。【参考方案4】:

当 tomcat 内存不足时会出现此问题,即 tomcat 配置的内存少于运行应用程序所需的应用程序。

所以要克服这个问题,请转到 tomcat bin 目录创建一个新文件 setenv.bat 并在该文件中定义 PermSize,如下所示:

设置 JAVA_OPTS=-Dfile.encoding=UTF-8 -Xms512m -Xmx1024m -XX:PermSize=512m -XX:MaxPermSize=1024m

PermSize 可以根据应用需求设置更大的范围。

【讨论】:

以上是关于什么是 OutOfMemoryError 以及如何调试和修复它的主要内容,如果未能解决你的问题,请参考以下文章

Android 应用程序中的 OutOfMemoryError

既然JVM有Full GC,为什么还会出现OutOfMemoryError?

了解OutOfMemoryError异常 - 深入Java虚拟机读后总结

jvm有fullGc 为什么还会出现oom(OutOfMemoryError)

多个项目MyEclipse中启动出现OutOfMemoryError: PermGen space如何解决

如何判断我是否接近使用jmap的OutOfMemoryError?