OOM :内存溢出

OOM,即OutOfMemory,内存溢出
原因是:分配的太少;用的太多;用完没释放。

常见的情况有三种:

1. java.lang.OutOfMemoryError: Java heap Metaspace
方法区溢出了,一般出现于大量Class或者jsp页面,或者采用cglib等反射机制的情况,因为上述情况会产生大量的Cl信息存储于方法区。此种情况可以通过更改方法区的大小来解决,另外,过多的常量也会导致方法区溢出。

2.java.lang.OutOfMemoryError: Java heap space

java堆内存溢出,此种情况最常见,一般由于内存泄露或者堆的大小设置不当引起。对于内存泄露,需要通过内存监控软件查找程序中的泄露代码,而堆大小可以通过虚拟机参数-Xms,-Xmx等修改。

3.java.lang.StackOverflowError

不会抛OOM error,但也是比较常见的Java内存溢出。JAVA虚拟机栈溢出,一般是由于程序中存在死循环或者深度递归调用造成的,栈大小设置太小也会出现此种溢出。可以通过虚拟机参数-Xss来设置栈的大小。

解决方案:

1.直接内存溢出

直接内存(DirectMemory)容量可以通过-XX : MaxDirectMemorySize指定,如果不指定,则默认与Java最大堆(-Xmx指定)一样。
由于直接内存(DirectMemory)导致的内存溢出,一个明显的特征是在Heap Dump文件中不会看见明显的异常,如果发现OOM之后Dump文件很小,而程序中又直接或间接使用了NIO,就可以考虑检查一下是否为直接内存(DirectMemory)溢出异常。

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

方法区用于存放Class的相关信息,如类名、访问修饰符、常量池、字段描述、方法描述等。当前的一些主流框架,如Spring、Hibernate,对于类进行增强的时候都会使用到CGLib这类字节码技术,增强的类越多,就需要越大的方法区来保证动态生成Class可以加载入内存,这样的情况下可能会造成方法区的OOM异常。
在经常动态生成大量Class的应用中,需要特别注意类的回收状况

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

StackOverflowError :如果线程请求的栈深度超过了虚拟机所允许的最大深度,就会抛出该异常;

OutOfMemoryError:如果虚拟机在拓展栈的时候,无法申请到足够的空间,就会抛出该异常。

当在单线程环境下,无论是由于栈帧太大还是虚拟机栈容量太小,当内存无法继续分配的时候,虚拟机抛出的都是StackOverflowError 异常。
在多线程环境下,如果为每个线程的栈分配的内存越大,反而越容易产生OOM异常。每个线程分配到的栈容量越大,可以建立的线程数量就自然减少了,那么在新建立线程的时候就很容易把内存耗尽,产生OOM异常。虚拟机默认参数栈深度大多数情况下能够达到1000~2000,对于正常的方法调用(包括递归)是完全够用的。但是,在多线程环境下的OOM,就只能通过减少最大堆和减少栈容量来换取更多的线程数量。