1、堆溢出
绝大部分的内存溢出属于堆溢出,原因是大量对象占用了堆空间,而这些对象持有强引用,无法回收。-Xmx参数指定堆空间大小小于对象大小时候,溢出自然而然的就发生了。
报错信息:java.lang.OutOfMemoryError: Java heap space
为了减少堆溢出错误,一方面可以使用-Xmx指定一个更大的堆空间。另外可以通过MAT或者VisualVM等工具,找到大量占用堆空间的对象,并在代码上合理优化。
2、直接内存溢出
在Java的NIO中,支持直接内存使用,也就是通过Java代码获取一块堆外内存,该内存是直接向操作系统申请的。直接内存申请速一般比堆内存慢,但是访问速度快于堆内存,因此对于那些可以复用经常访问的空间,使用直接内存可以提高系统的性能,但是由于该内存没有JVM托管,使用不当容易触发直接内存溢出,导致宕机。
-XX:+PrintGCDetails 输出GC详情
报错信息:java.lang.OutOfMemoryError: Direct buffer memory
直接内存不一定触发GC,触发直接内存使用量达到-XX:MaxDirectMemorySize的设置值。所以保证内存不溢出就需要合理的进行FullGC。或者设订一个系统可达的-XX:MaxDirectMemorySize值。通过显示的gc是可以回收直接内存的。
在不使用-XX:MaxDirectMemorySize设置最大最直接内存空间的时候,默认情况最大可用直接内存等于-Xmx即堆空间的大小。
避免直接内存溢出:
1、合理的GC
2、设置系统容许的-XX:MaxDirectMemorySize
3、设置小的-Xmx
3、过多线程导致OOM
线程的栈空间也是在堆外分配的,和直接内存非常相似,如果想让系统支持更多的线程,那么应该使用一个较小德尔堆空间。
报错信息: unable to create new native thread
原因是Java进程达到了可使用的内存上限。减少堆空间,减少线程占用的占空间使用-Xss参数可以指定线程的栈空间。
-Xmx1g -Xss128k 堆空间还是1g,但是线程栈空间减少到128k,剩余的可用内存里可以容纳更多的线程。
4、MetaspaceOOM
Metaspace元空间主要存储类的元数据信息,例如:类型、属性、方法、访问限制等。可见Metaspace空间增长是由于反射类加载、动态代理生成的类加载等导致的,也就是说Metaspace的大小和加载的数据有关,加载的类越多metaspace占用的内存也就越大。
-XX:+TraceClassLoading -XX:+TraceClassUnloading可以记录类加载和卸载的情况。
5、GC效率低导致OOM
GC 是内存回收的关键,如果GC效率地下,那么系统的性能会收到严重的影响。如果堆空间太大,GC所花费的时间就会较多,并且回收释放的对象较少,虚拟机认为GC效率地下的可能抛出OOM,当遇到一下情况时候,抛出GC overhead limit exceeded.
1、花费在GC上的时间超过98%
2、老年代释放内存是否小于2%
3、eden区释放内存是否小于2%
同时出现上述case。