生产环境中,最常见的一种案例就是OOM,也叫「内存溢出」,它表示JVM已经无法支撑业务系统的运行。而很多工程师都没有类似处理线上系统故障的经验,尤其是这种突发的故障。那么:
1、为什么会OOM?(Why)
2、发生什么样的OOM?(What)
3、那个系统发生的OOM?(Who/Where)
4、什么时候发生的OOM?(When)
5、怎么排查和解决OOM?(How)
我们知道,启动一个Java系统,就是启动一个JVM进程。由这个JVM进程来决定如何执行Java代码,一个JVM进程只有一个执行入口:它总是从main方法开始的。
JVM启动后默认的main线程就是专门用于执行main方法的主线程。
1、Metaspace用于存放系统使用到的各种类信息和JDK自身的一些信息(可能发生OOM的地方);
2、每个线程都有自己的栈帧,用于存放各种局部变量(也可能发生OOM的地方);
3、另外,代码创建的各种对象,都会存放到堆内存里(也可能发生OOM的地方)。
所以,总结起来,OOM可能发生的地方包括:
1、Metaspace区
2、栈帧
3、堆内存
可以通过参数来设置Metaspace区的大小,防止产生OOM:
-XX:MetaspaceSize=512M -XX:MaxMetaspaceSize=512M
Metaspace区大小相对固定,很少出现大的浮动。Metaspace区满了也会触发Full GC,一旦Metaspace无法回收空间且还在不停加载更多数据,就会发生OOM。
Metaspace发生OOM的常见原因有:
1、新手工程师未设置Metaspace区的大小,而是直接使用的默认值;
2、使用的框架用到了cglib之类的技术通过反射动态生成很多附加类,导致Metaspace区被占满。
而栈帧发生OOM的常见原因有:
1、方法发生递归调用时,导致频繁入栈出栈;
2、即便是同一个方法,每一次调用都会产生一个入栈操作,调用完成后又会产生出栈操作。