JVM 系列文章的第一篇。敬请期待后续。
故障描述某年某月某日 上午,线上发生故障,经过排查,发现某核心服务 Dubbo 接口超时。
故障根源查看该服务监控指标,发现该服务 FullGC 次数过于频繁,简直要上天了。那也难怪接口会超时了。
那么为啥 FullGC 次数太多会造成接口超时呢?
因为 GC 停顿。 FullGC 时会产生GC停顿,也叫 stop the world。简称 STW ,是指在执行垃圾收集算法时,用户线程都被挂起。这也不难理解为啥 频繁 FullGC 会引起服务超时了。
深入探究那么为什么会引起频繁FullGC 呢?
回答这个问题之前,先了解下,有哪些情况会触发 Full GC ?
- 老年代内存空间不足时,会触发 FullGC.
- 永久代/metaspace 内存空间不足时,也会触发FullGC.
- 显示调用 GC,System.gc().(会建议jvm GC,但是不一定会GC).
产生 FullGC 的基本原因就上面三种。
故障服务就是创建很多对象,无法回收,导致内存不足,然后 GC 回收不了时,就会引起频繁 FullGC 了。
复现故障根据内存不足创建对象会引起 FullGC 的原理,写了一个 Demo ,观察GC 情况。
代码如下:
代码很简单,就是让上次创建的对象可以被回收,然后继续创建对象,然后链接到根结点,使其不会被回收。demo 地址
使用启动参数 -Xms512m -Xmx512m 设置堆内存大小。
启动 Demo ,然后发起请求,观察GC 情况。
首先,使用命令 jps -l 查看进程ID
然后使用 jstat 命令查看GC信息 (jstat 命令详解):
上图可以看到 正在不停的进行 Full GC.
上图可以看出,老年代,以及元数据区 内存空间已满,这也是 不停 Full GC 的原因。
再看我发出的请求:
过去这么久,依然没有结果。
使用 jstack 命令查看 线程状态,发现 用户线程已经被挂起。
不难看出,频繁的 FullGC 已经影响到了应用的正常运行。



