记一次,线上服务频繁FGC排查过程

一、问题

最近接到运营部门的反馈网站时常会出现小批量的502且在网站出现502以前反应特别慢,刷新几回之后又能够正常访问了。正则表达式

二、排查过程

项目部署了两台机器,其中一台出现重启的状况,部分用户在访问当前服务器时正好机器重启了,致使访问异常。数组

2.一、查看日志文件

查看生产环境日志发现其中一台机器重启了屡次,从warpper log中能够发现warpper在屡次ping不通时自动重启了屡次,从运维那边确认这台服务器屡次出现无响应的状况。此时第一时间想到OOM进一步查看日志并无发现OutOfMemoryException抛出,也没有StackOverflowExceptionbash

2.二、生产环境资源、GC状况

经过top命令查看生产环境CPU占用一直很是高,load也一直高居不下,GC长时间占用CPU资源。服务器

image

进一步查看GC状况,发如今重启后很短的时间内FGC 次数达7W+;Old Generation 持续占用100%,而每次FGC的时间又很是的短.运维

jstat -gcUtil [pid] 1000jvm

image

在经过jmap -histo [pid]查看内存实例状况也没有发现异常。工具

image
是什么致使如此频繁的 FGC?。

2.三、查看堆栈信息

因为没有触发OOM手动添加如下启动参数,打印FGC 先后堆内存状况优化

-XX:+HeapDumpBeforeFullGC
-XX:+HeapDumpAfterFullGC
-XX:HeapDumpPath=/tmp
复制代码

果真,重启后短期内开始输出 dump网站

接下来使用jvisualvm (JDK 自带的内存分析工具) 查看堆dump文件。 如下列出FGC先后的堆dump类视图spa

  • FGC前
    image
  • FGC后
  • image

对比FGC先后发如今FGC以前存在大量的int[]char[]数组,且数组的length都很是大,而这些大数组在FGC以后又被有效的回收了。对jvm垃圾回收有了解的同窗应该知道,jvm为了不频繁的移动大对象会将大对象直接建立在Old Generation。此时开始怀疑是否是Old Generation的空间不够了,逐一排查线上环境的jvm启动参数。

-Xms 2048
-Xmx 2048
...

-Xmn 2000
-
复制代码

image

......

最后发现,因为这台机器内存只有2G而新生代分配的内存却达到了2000M剩下的内存只有48M。而大数组又会直接分配到Old GenerationOld Generation没有足够的空间来存放大数组对象时,就可能触发FGC修改 -Xmn 683默认新生代和老年代的比值为1:2。从新发布问题解决,topjstat -gc查看服务器状态各项数据都很是可爱。

三、复盘

因为项目已经跑了好几年,一开始的思路都在查找项目代码层面的问题,丝毫没有意Jvm启动参数的问题,其实对一些有经验的同窗来讲发现问题搜集到的一些信息就能够定位问题。如:

  1. GC那张图就能够明显的看出问题。FGC 异常频繁(7W+),但FGCT却不高(1.9W),这说明每次 FGC的效率很是高。而每次FGC的时候New Generation的占用却很是少,能够排除是由于程序问题短期内产生大量新对象触发的 FGC,这些都提供了直接的排查方向应该从:致使FGC 触发的条件入手,而不是找程序的问题。
  2. dump中存在大量无引用的对象,也从侧面反应出在FGC以前没有有效的触发YGC

还有一点值得注意,jvm启动参数的默认值在绝大多数状况下均可以完美的运行,不到系统优化的最后一步尽可能使用默认配置,最后还有一点疑问大量的int[]char[]数组是从那里来得?经过分析项目中的代码,以及FGC前存在大量的pattern(正则表达式)相关对象分析,初步怀疑是由于项目中大量不规范的使用Pattern致使的。

四、总结排查过程

  1. 查看日志是否有OutOfMemoryExceptionStackOverflowException抛出。
  2. 查看线上服务器状态、GC状况。
  3. 分析GC先后的dump文件。
  4. 定位问题。
相关文章
相关标签/搜索