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

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


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

OutOfMemoryError是Java虚拟机(JVM)抛出的exception,因为它需要为(新)对象分配内存,但对象没有足够的内存可用。 JVM首先尝试通过运行垃圾收集器来释放死对象使用的内存。

由于OutOfMemoryErrorVirtualMachineError ,因此允许JVM随时抛出它 ,尽管它必须首先尝试通过垃圾收集释放内存 。

但是,在实践中,它很可能会从尝试创建无法分配内存的对象的new语句中抛出。 因此,您应首先检查与exception关联的堆栈跟踪,以获取有关问题原因的线索, 就像对任何其他exception一样 。

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

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

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

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

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

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

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

当tomcat内存不足时会发生此问题,即tomcat配置的内存较少,然后运行应用程序所需的应用程序。

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

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

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