GC 为什么要挂起用户线程? 什么愁什么怨?

GC 为什么要挂起用户线程? 什么愁什么怨?

GC 为什么要挂起用户线程? 什么愁什么怨?_第1张图片

前言

JVM 系列文章的第一篇。敬请期待后续。

故障描述

某年某月某日 上午,线上发生故障,经过排查,发现某核心服务 Dubbo 接口超时。

GC 为什么要挂起用户线程? 什么愁什么怨?_第2张图片

故障根源

查看该服务监控指标,发现该服务 FullGC 次数过于频繁,简直要上天了。那也难怪接口会超时了。

那么为啥 FullGC 次数太多会造成接口超时呢?

因为 GC 停顿。 FullGC 时会产生GC停顿,也叫 stop the world。简称 STW ,是指在执行垃圾收集算法时,用户线程都被挂起。这也不难理解为啥 频繁 FullGC 会引起服务超时了。

深入探究

那么为什么会引起频繁FullGC 呢?

回答这个问题之前,先了解下,有哪些情况会触发 Full GC ?

  1. 老年代内存空间不足时,会触发 FullGC.
  2. 永久代/metaspace 内存空间不足时,也会触发FullGC.
  3. 显示调用 GC,System.gc().(会建议jvm GC,但是不一定会GC).

产生 FullGC 的基本原因就上面三种。

故障服务就是创建很多对象,无法回收,导致内存不足,然后 GC 回收不了时,就会引起频繁 FullGC 了。

复现故障

根据内存不足创建对象会引起 FullGC 的原理,写了一个 Demo ,观察GC 情况。

代码如下:

GC 为什么要挂起用户线程? 什么愁什么怨?_第3张图片

代码很简单,就是让上次创建的对象可以被回收,然后继续创建对象,然后链接到根结点,使其不会被回收。demo 地址

使用启动参数 -Xms512m -Xmx512m 设置堆内存大小。

启动 Demo ,然后发起请求,观察GC 情况。

首先,使用命令 jps -l 查看进程ID

GC 为什么要挂起用户线程? 什么愁什么怨?_第4张图片

然后使用 jstat 命令查看GC信息 (jstat 命令详解):

GC 为什么要挂起用户线程? 什么愁什么怨?_第5张图片

上图可以看到 正在不停的进行 Full GC.

img

上图可以看出,老年代,以及元数据区 内存空间已满,这也是 不停 Full GC 的原因。

再看我发出的请求:

GC 为什么要挂起用户线程? 什么愁什么怨?_第6张图片

过去这么久,依然没有结果。

使用 jstack 命令查看 线程状态,发现 用户线程已经被挂起。

GC 为什么要挂起用户线程? 什么愁什么怨?_第7张图片

不难看出,频繁的 FullGC 已经影响到了应用的正常运行。

结束语

了解 JVM 还是很有必要的。CURD 不觉得什么,问题来临时就可以so easy 了。

GC 为什么要挂起用户线程? 什么愁什么怨?_第8张图片

你可能感兴趣的:(java)