JVM内存溢出

可能导致内存溢出的三个区域

  • Metaspace区域里发生OOM
  • 每个线程的虚拟机栈内存可能发生OOM的区域
  • 堆内存空间发生内存溢出

Metaspace区域

  1. 第一种原因,很多工程师他不懂JVM的运行原理,在上线系统的时候对Metaspace区域直接用默认的参数,即根本不设置其大小 这会导致默认的Metaspace区域可能才几十MB而已,此时对于一个稍微大型一点的系统,因为他自己有很多类,还依赖了很多外部的jar包有有很多的类,几十MB的Metaspace很容易就不够了
  2. 第二种原因,就是很多人写系统的时候会用cglib之类的技术动态生成一些类,一旦代码中没有控制好,导致你生成的类过于多的时候,就很容易把Metaspace给塞满,进而引发内存溢出

Metaspace区域发生内存溢出的一个场景,就是如果我们在程序里不停的动态生成类,就会导致不停的加载类到Metaspace区域里去,而且这些动态生成的类必须还得是不能被回收掉的。 接着一旦Metaspace区域满了,就会触发Full GC连带着回收Metaspace中的类,但是此时大量的类是不能被回收的。 因此即使触发过Full GC过后,Metaspace区域几乎还是不能放下任何一个类,此时必然会触发Metaspace区域的内存溢出,导致JVM 也是崩溃掉,无法继续运行了。

栈内存区域

​ 一个线程的虚拟机栈内存大小是有限的,比如1MB,那么假设你不停的让这个线程去调用各种方法,然后不停的把 方法调用的栈桢压入栈中,那么如果不停的让线程调用方法,不停的往栈里放入栈桢,此时终有一个时刻,大量的栈桢会消耗完毕这个1MB的线程栈内存,最终就 会导致出现栈内存溢出的情况。

堆内存区域

​ 有限的内存中放了过多的对象,而且大多数都是存活的,此时即使GC过后还是大部分都存活,所以要继续放入更多对象已经不可能 了,此时只能引发内存溢出问题。 所以一般来说发生内存溢出有两种主要的场景:

  1. 系统承载高并发请求,因为请求量过大,导致大量对象都是存活的,所以要继续放入新的对象实在是不行了,此时就会引发OOM系统崩溃

  2. 系统有内存泄漏的问题,就是莫名其妙弄了很多的对象,结果对象都是存活的,没有及时取消对他们的引用,导致触发GC还是无法回收,此时只能引发内存溢出,因为内存实在放不下更多对象了

    因此总结起来,一般引发OOM,要不然是系统负载过高,要不然就是有内存泄漏的问题