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。