Java堆溢出

Java堆用于存储对象实例,在对象数量到达最大堆的容量限制后就会产生内存溢出异常。




  • 如果是内存泄漏,可以通过工具查看泄漏的对象到GC Roots的引用链,确定对象为何无法被垃圾收集器自动回收。
  • 若果不存在内存泄漏,就需要通过参数调优,对比机器物理内存,确定分配的堆内存是否可以调大,同时要从代码层间检查是否有某些对象的生命周期过长,保持的状态时间过长等情况,尝试减少程序运行期间的内存消耗。

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

Hotspot虚拟机不区分虚拟机栈和本本地方法栈,所以虽然存在-Xoss(设置本地方法栈大小),但实际不起作用。


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






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

JDK1.7开始逐步"去永久代"
在JDK1.6及之前,可以通过限制方法区大小,从而间接限制常量池的容量。
String.intern(),一个Native方法,不断执行此方法往常量池中添加字符串,可以导致PermGen Space OOM,即运行时常量池属于方法区(Hotspot JVM 永久代)的一部分。
当前很多的主流框架如Spring、Hibernate,在对类进行增强的时候,都会使用到CGLib这类字节码技术,增强的类越多,就需要越大的方法区类保证动态生成的Class可以载入的内存中。

本机直接内存溢出

DirectMemo如容量可以通过-XX:MaxDirectMemorySize 指定,默认为Java堆最大内存(-Xmx)。
由于DirectMemory导致的内存溢出,一个明显的特征就是Heap Dump文件中不会看到明显的异常,如果发现OOM之后Dump很小,而程序中又直接或者间接使用了NIO,那么可以考虑是这方面的原因。