线上服务器OOM问题排查记录

前言

去年公司范围内迁移redis -> codis时, 顺手整理了一遍公用service的pom依赖, 抽离了公用的依赖. 升级了Spring版本:3.x -> 4.x . 升级了JAVA编译版本:1.7 -> 1.8 (可以享用新的集合API, 流等). 但是tomcat的JVM配置参数还是旧的1.7版本.

JVM配参对比1.7与1.8版本之间的最大变化莫过于Perm区的移除, Metaspace的新增. 新增了G1GC辣鸡收集器. 便一直想着追潮流升级一下, 找时间去优化一下JVM配参.

操作

一台机器报了OOM-heap space异常, 在调整了 -Xmx-Xms 参数之后觉得有必要去搞一下新的JVM配参了. 于是改了几个tomcat实例的参数然后重启. 参数如下:

旧参数:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
-Djava.util.Arrays.useLegacyMergeSort=true
-server
-Xmx512m
-Xms512m
-Xmn256m
-Xss512k
-XX:PermSize=64m
-XX:MaxPermSize=128m
-XX:+UseConcMarkSweepGC
-XX:+UseParNewGC
-XX:CMSFullGCsBeforeCompaction=5
-XX:+UseCMSCompactAtFullCollection
-XX:+PrintGCDetails
-XX:+PrintGCTimeStamps
-Xloggc:xxxxxxxxxxxxx
-XX:+HeapDumpOnOutOfMemoryError
-XX:HeapDumpPath=xxxxxxxxxxxxxx

新参数(由于机器最近由8G内存升了16G, 空闲了很多内存资源, heap可以开大点):

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
-Djava.util.Arrays.useLegacyMergeSort=true
-server
-Xmx1024m
-Xms1024m
-Xss512k
-XX:MaxMetaspaceSize=128m
-XX:+UseG1GC
-XX:-UseAdaptiveSizePolicy
-XX:+DisableExplicitGC
-XX:+UseFastAccessorMethods
-verbose:gc
-XX:+PrintGCDetails
-XX:+PrintGCDateStamps
-XX:+PrintGCTimeStamps
-XX:+UseGCLogFileRotation
-XX:GCLogFileSize=256M
-XX:NumberOfGCLogFiles=4
-Xloggc:xxxxxxxxxxxx
-XX:+HeapDumpOnOutOfMemoryError
-XX:HeapDumpPath=xxxxxxxxxxx

问题

  1. 改了几台服务器, 运行一段时间后部分重量级业务模块报了OOM-MetaSpace异常, 并且服务响应卡顿, dump堆文件与top命令排查后发现问题主要是MetaSpace满了反复触发GC, 导致GC线程占用CPU过高. 发现后便立即调大了-XX:MaxMetaspaceSize参数, 并且找了一个tomcat实例加上了一些VisualVM监控参数, 观察了一段时间. 问题得以解决.
  2. 运行一段时间后一台服务器上的tomcat反复报java.lang.OutOfMemoryError: unable to create new native thread 异常. 而且跳板机登录上去后查看机器剩余内存还是很多. 没有什么头绪, 便调小了这台机器的部分tomcat实例内存大小, 空闲出了更多内存避免问题产生.

解决

第二天这台机器又报出了java.lang.OutOfMemoryError: unable to create new native thread 异常. 拉楼上的OP君下来一起排查问题.OP君使用lsof命令发现一个tomcat实例占用了八千多个连接, 找到了进程, kill然后重启, 问题解决.

分析

原因是socket泄露, 太多的socket未关掉(具体原因未知), JVM在创建线程时无法创建socket???(待查明), 报了java.lang.OutOfMemoryError: unable to create new native thread 异常.