OOM的常见原因

| 分类 Java  | 标签 JVM 

java.lang.OutOfMemoryError这个异常我相信大部分开发人员都有遇到过,通过本文希望读者能快速解决OOM问题。

Java堆溢出

Java堆用于存储对象实例,只要不断创建对象,且保证GC Roots到对象这件有可达路径来避免垃圾回收机制清除这些对象,那么在对象数量到达最大堆的容量限制后就会产生内存溢出异常。

通过参数 -XX:+HeapDumpOnOutOfMemoryError可以让虚拟机在出现内存溢出时Dump出当前内存堆转储快照以方便事后分析。

用工具(如Eclipse Memory Analyzer)查看泄露对象到GC Roots的引用链;就能找到泄露对象是通过怎么的路径与GC Roots相关联并导致垃圾回收器无法自动回收他们的。

若不存在泄露,就要检查虚拟机的堆参数了(-Xmx与-Xms)。

虚拟机栈和本地方法栈溢出

关于虚拟机栈和本地方法栈,在虚拟机规范中描述了两种异常:

  • 若线程请求的栈深度大于虚拟机所允许的最大深度,将抛出 StackOverflowError异常
  • 若虚拟机在扩展栈时无法申请到足够的内存空间,则抛出OutOfMemoryError异常。

方法区和运行时常量池溢出

方法区存放的是Class相关的信息,如类名、访问修饰符、常量池、字段描述、方法描述等。如果运行时有大量的类, 那么方法区可能出现OOM。一个类要被垃圾收集器回收掉,判定条件比较苛刻,经常动态生成大量Class的应用中,要特别注意类的回收状况。

本机内存直接溢出

明显特征是Heap Dump文件中不会看到明显异常,若发现OOM后的Dump很小,并且程序中直接或间接使用了NIO,那么就要考虑一下是不是这方面的原因。


上一篇     下一篇