原创

排查FGC问题实践

1. 清楚从程序角度,有哪些原因导致FGC?

大对象:系统一次性加载了过多数据到内存中(比如SQL查询未做分页),导致大对象进入了老年代。

内存泄漏:频繁创建了大量对象,但是无法被回收(比如IO对象使用完后未调用close方法释放资源),先引发FGC,最后导致OOM。

程序频繁生成一些长生命周期的对象,当这些对象的存活年龄超过分代年龄时便会进入老年代,最后引发FGC。

程序BUG导致动态生成了很多新类,使得 Metaspace 不断被占用,先引发FGC,最后导致OOM。

代码中显式调用了gc方法,包括自己的代码甚至框架中的代码。

JVM参数设置问题:包括总内存大小、新生代和老年代的大小、Eden区和S区的大小、元空间大小、垃圾回收算法等等。

2. 清楚排查问题时能使用哪些工具

公司的监控系统:大部分公司都会有,可全方位监控JVM的各项指标。

JDK的自带工具,包括jmap、jstat等常用命令:
# 查看堆内存各区域的使用率以及GC情况 jstat -gcutil -h20 pid 1000

# 查看堆内存中的存活对象,并按空间排序jmap -histo pid | head -n20

# dump堆内存文件jmap -dump:format=b,file=heap pid

可视化的堆内存分析工具:JConsole、JVisualVM、jvmstat、Java mission control、MAT等

3. 排查指南

查看监控,以了解出现问题的时间点以及当前FGC的频率(可对比正常情况看频率是否正常)

了解该时间点之前有没有程序上线、基础组件升级等情况。

了解JVM的参数设置,包括:堆空间各个区域的大小设置,新生代和老年代分别采用了哪些垃圾收集器,然后分析JVM参数设置是否合理。

再对步骤1中列出的可能原因做排除法,其中元空间被打满、内存泄漏、代码显式调用gc方法比较容易排查。

针对大对象或者长生命周期对象导致的FGC,可通过 jmap -histo 命令并结合dump堆内存文件作进一步分析,需要先定位到可疑对象。

通过可疑对象定位到具体代码再次分析,这时候要结合GC原理和JVM参数设置,弄清楚可疑对象是否满足了进入到老年代的条件才能下结论。

本文链接地址:http://www.ysxbohui.com/article/18

正文到此结束