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

8

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


许多初学Java的人都很难应对OutOfMemoryError。本文试图创建一个规范问题,回答关于OutOfMemoryError最常见的问题。我创建这个新问题,而不是改编以前关于OutOfMemoryError的众多问题之一,因为那些问题及其答案与一个人遇到的特定问题紧密耦合。
此问题与调试异常的通用建议不同,因为问题的原因并不总是在调用堆栈上,需要具体的建议。

2
踩下投票。有趣。好像有些人不想创建一个规范的问题。 - Raedwald
4
我相信人们想要一个标准问题,只是不想要你的标准问题。 :-P (我不是那些投反对票的人之一。) - C. K. Young
6
这个网站上已经有大约十几个问题是关于如何处理Java中的“OutOfMemoryError”。再添加一个会对任何人有帮助吗? - Dawood ibn Kareem
1
@DavidWallace 如果你让所有其他的副本都指向这个问题,它就可以成为一个规范问题。(我并不是在赞成这个问题成为一个规范问题,只是支持规范问题的概念。) - C. K. Young
1
@DavidWallace 大多数 OOME 问题都涉及非常具体的问题,不一定会得到通用的答案。我认为创建一个可以用作重复的规范问答是一个好主意。 - assylias
显示剩余3条评论
4个回答

13

OutOfMemoryError是Java虚拟机(JVM)抛出的异常,因为它需要为一个(新的)对象分配内存,但是该对象所需的内存不足。 JVM首先尝试通过运行垃圾回收器来释放已经死亡对象所使用的内存。

由于OutOfMemoryErrorVirtualMachineError,因此JVM允许在任何时候抛出该异常, 但必须首先尝试通过垃圾回收释放内存

然而,在实践中,它可能会被从一个试图创建无法分配内存的对象的new语句中抛出。因此,您应该首先检查与异常相关联的堆栈跟踪,以获取有关问题原因的线索,就像处理其他任何异常一样
  • 如果异常是由于尝试分配一个数组(例如int[] values = new int[n])而抛出的,则原因可能是您正在尝试创建一个过大的数组(n 太大了)。您在计算所需数组大小时是否犯了错误?
  • 如果异常是由于在另一个人编写的容器类的方法中尝试分配一个数组而抛出的,则原因可能是您的代码要求容器存储过多的东西。例如ArrayList.reserve(int)HashMap(int)等方法必须为将来使用分配存储空间。您在计算所需容器大小时是否犯了错误?
  • 如果异常是从循环内部抛出的,则原因可能是代码循环次数太多。您的循环终止条件是否正确?如果是for循环,您是否要求它循环正确的次数?
如果堆栈跟踪无法提供足够的线索,您可以尝试使用堆分析器。这是一种监视程序,使您能够在程序运行时检查用于对象的内存,或检查程序退出时编写的堆转储。它可以提供有关存储在内存中的对象的大小、数量和类的信息。
JVM有一个预先分配的有限内存。您可能会得出结论,您的程序的行为正确,但需要比提供给它的内存更多的内存才能运行。如果您没有明确告诉JVM要使用多少内存,大多数实现将选择基于计算机RAM量的合理默认值,但该值对于您的程序可能太小了。 JVM的命令行选项可以控制可用的内存量。对于大多数JVM实现来说,其中最重要的选项是-Xmx-Xms

“the JVM” 中的“the”是否排除了其他 JVM,比如 Dalvik,它们也可能抛出相同的 OutOfMemory 异常? - mehmetminanc
@MehmetM.Inanc 不,JVM并不仅指HotSpot。 - C. K. Young
1
过度递归会导致 StackOverflowError,而不是 OutOfMemoryError - C. K. Young
过度递归会导致StackOverflowError,如果没有先引发OutOfMemoryError的话! - Raedwald

9
为了调试OutOfMemoryError,可以使用-XX:+HeapDumpOnOutOfMemoryError选项调用JVM,当发生OutOfMemoryError时,将导致堆转储被写出。然后使用像VisualVMjhatfasthat这样的工具来查看堆转储。
您还可以使用-dump选项使用jmap在任何时候手动生成堆转储。 披露:我是fasthat的维护者,它是jhat的一个分支。

0

当Tomcat的内存配置小于应用程序所需的内存时,就会出现这个问题。

为了解决这个问题,请进入Tomcat bin目录创建一个新文件setenv.bat,在该文件中定义PermSize如下:

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

根据应用程序的要求,可以将PermSize设置为更高的范围。


0
当应用程序资源耗尽JVM堆分配的内存时,将抛出OutOfMemoryException异常。尝试增加JVM堆大小。

@BigMike 这些情况实际上也是堆的一部分。 :-) - C. K. Young
@ChrisJester-Young:我曾经遇到过一个与GC相关的问题,它不仅仅与堆大小有关,而且完全取决于其中小对象的数量。 - BigMike

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接