一次java.lang.OutOfMemoryError:Metaspace处理
其实这个问题非常明显就是Metaspace内存不够导致溢出,调整jvm的-XX:MetaspaceSize=56m -XX:MaxMetaspaceSize=128m元空间大小参数就能解决。但是根据甲方要求,必须要给出明确的解释,排除是否是内存泄露导致的OutOfMemoryError: Metaspac报错。没有办法,甲方爸爸的要求。那就找点证据说明就是内存给小了的问题。
由于之前的容器已经清除,只能在配置一样的环境中分析。
首先查看当前jvm Metaspace分配的空间大小。我是通过arthas的jvm命令进行查看的。
首先拉去arthas的jar包。
1 | curl -O https://arthas.aliyun.com/arthas-boot.jar |
然后将jar复制到你要查看项目的docker容器中去
1 | docker cp ./arthas-boot.jar {容器名称或id}:/home/ |
进入容器
1 | docker exec -it {容器名称或id} sh |
启动arthas-boot.jar
1 | java -jar arthas-boot.jar |
看到以上证明启动成功
输入jvm查看jvm信息
和启动配置是一致的。(退出arthas最好使用stop,不然在其他docker中启动会监控的依然是这个项目。)
arthas文档地址:https://arthas.aliyun.com/doc/install-detail.html 这个工具功能还有很多比如监控代码执行时间等等。
接下来使用jstat查看项目的gc状况
在容器中输入jps,然后就可以使用jstat命令查看。输入jstat -gcutil pid查看gc概要信息
列名称 | 描述 |
---|---|
S0 | S0(Survivor 0)空间使用百分比(相对于当前容量) |
S1 | S1(Survivor 1)空间使用百分比(相对于当前容量) |
E | Eden空间使用百分比(相对于当前容量) |
O | 老年代空间使用百分比(相对于当前容量) |
M | 元空间(Metaspace)使用百分比(相对于当前容量) |
CCS | CCS空间使用百分比 |
YGC | 新生代GC(Minor GC/Young GC)发生的次数 |
YGCT | YGC所消耗的时间, 单位s |
FGC | Full GC发生的次数 |
FGCT | Full GC消耗的时间, 单位s |
GCT | 所有GC消耗的总时间, 单位s |
通过上图分析新生代发生了大量的gc,导致老年代数据快速积压,然后发生Full GC。
接下来将jvm的加载类使用jmap dump下来到本地分析查看。
1 | jmap -dump:live,format=b,file=dump.hprof 6 |
可以看到本地生成了个dump.hprof 文件
将它拉取到本地,使用JProfiler打开
JProfiler官网:https://www.ej-technologies.com/products/jprofiler/overview.html
这些类点进去看看是否有大量创建的异常类
发现没有异常创建的类,分析就是单纯的空间给小了。加大元空间容量分配-XX:MetaspaceSize=256m -XX:MaxMetaspaceSize=512m 再运行2天看看gc状况
发现新生代gc2w多次,Full GC次数为0,gc大部分都发生在新生代。说明配置有效。
这是我第一次实战调优,要是哪里有问题请指出,互相学习一下。