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

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

img

前言

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

故障描述

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

img

故障根源

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

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

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

深刻探究

那么为何会引发频繁FullGC 呢?spa

回答这个问题以前,先了解下,有哪些状况会触发 Full GC ?.net

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

产生 FullGC 的基本缘由就上面三种。线程

故障服务就是建立不少对象,没法回收,致使内存不足,而后 GC 回收不了时,就会引发频繁 FullGC 了。对象

复现故障

根据内存不足建立对象会引发 FullGC 的原理,写了一个 Demo ,观察GC 状况。blog

代码以下:

img

代码很简单,就是让上次建立的对象能够被回收,而后继续建立对象,而后连接到根结点,使其不会被回收。demo 地址

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

启动 Demo ,而后发起请求,观察GC 状况。

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

img

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

img

上图能够看到 正在不停的进行 Full GC.

img

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

再看我发出的请求:

img

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

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

img

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

结束语

了解 JVM 仍是颇有必要的。CURD 不以为什么,问题来临时就能够so easy 了。

img

相关文章
相关标签/搜索