一、背景
系统会偶现下面Metaspace区OOM的情况,服务器在重启后就会立马恢复,而且后面基本不会再复现,可能过了一两个月,又会偶现这个问题:
二、原因定位
2.1 jvm参数
先看下应用的jvm参数,采用的是默认的配置MaxMetaspaceSize=256m,按照经验来看,这个值偏小,但是理论上是够用的。那继续分析下是什么原因导致偶发性的OOM。
2.2 监控
切换到单机查看Metaspace区监控,发现在服务启动后,Metaspace区使用量在逐步缓慢的增长。应用仅仅在服务器启动后,Metaspace区内存占用会上涨一截。但不会有后面持续一天的增长呀。看看是哪块代码在捣乱~
2.3 dump内存
为了分析,分别在FGC前后dump两次,用来作对比分析。
2.4 分析dump文件
打开zprofile,开始分析,左边是第一次dump的文件,右边是第二次dump的文件。在按类型聚合后的ClassLoaderData这个维度,对比了所有的类加载器,发现DynamicJarClassLoader这个类加载器在FGC前后变化最大,基本确定是这个类无疑了。
同时在重复类列表,可以清楚的看到同属于fc包下面的类被重复加载了高达一千多次。
同时在服务器的日志里面也可以发现这些类的身影
2.5 代码分析
至此,可以猜测是fcbuservice的包会启动一个定时任务不停的加载类导致内存上涨,下面去分析下代码。首先找到DynamicJarClassLoader类,搜下引用
在截图类里面找到了之前猜想的定时任务,这个线程是60秒执行一次。而且线程里面加载的类名是通过远程接口拉取的,目前在线下拉取的结果应该是空的,所以线下环境没有日志,Metaspace区也不会上涨。
三、结论
Metaspace频繁加载和FGC,会导致内存碎片越来越多,定时任务不停的加载,肯定会导致内存碎片随着时间增长而变的越来越多,再加上服务器本身的Metaspace区剩余空间不是很大,跑了几个礼拜后,就有可能发生OOM的问题了。为解决这个问题,首先要增加Metaspace空间,可立即解决这个问题。同时需要对应责任人优化这块代码逻辑,不要反复加载,仅发生变化再加载,就更优雅了。