线上FullGC频繁的排查

简介: 线上FullGC频繁的排查:前段时间发现线上的一个dubbo服务Full GC比较频繁,大约每两天就会执行一次Full GC。

线上FullGC频繁的排查

问题

前段时间发现线上的一个dubbo服务Full GC比较频繁,大约每两天就会执行一次Full GC。

Full GC的原因

我们知道Full GC的触发条件大致情况有以下几种情况:

  1. 程序执行了System.gc() //建议jvm执行fullgc,并不一定会执行
  2. 执行了jmap -histo:live pid命令 //这个会立即触发fullgc
  3. 在执行minor gc的时候进行的一系列检查
执行Minor GC的时候,JVM会检查老年代中最大连续可用空间是否大于了当前新生代所有对象的总大小。
如果大于,则直接执行Minor GC(这个时候执行是没有风险的)。
如果小于了,JVM会检查是否开启了空间分配担保机制,如果没有开启则直接改为执行Full GC。
如果开启了,则JVM会检查老年代中最大连续可用空间是否大于了历次晋升到老年代中的平均大小,如果小于则执行改为执行Full GC。
如果大于则会执行Minor GC,如果Minor GC执行失败则会执行Full GC
  1. 使用了大对象 //大对象会直接进入老年代
  2. 在程序中长期持有了对象的引用 //对象年龄达到指定阈值也会进入老年代

对于我们的情况,可以初步排除1,2两种情况,最有可能是4和5这两种情况。为了进一步排查原因,我们在线上开启了 -XX:+HeapDumpBeforeFullGC。

    注意:
    JVM在执行dump操作的时候是会发生stop the word事件的,也就是说此时所有的用户线程都会暂停运行。
    为了在此期间也能对外正常提供服务,建议采用分布式部署,并采用合适的负载均衡算法

JVM参数的设置:

线上这个dubbo服务是分布式部署,在其中一台机子上开启了 -XX:HeapDumpBeforeFullGC,总体JVM参数如下:

-Xmx2g 
-XX:+HeapDumpBeforeFullGC 
-XX:HeapDumpPath=. 
-Xloggc:gc.log 
-XX:+PrintGC 
-XX:+PrintGCDetails 
-XX:+PrintGCDateStamps 
-XX:+UseGCLogFileRotation 
-XX:NumberOfGCLogFiles=10 
-XX:GCLogFileSize=100m 
-XX:HeapDumpOnOutOfMemoryError 

Dump文件分析

dump下来的文件大约1.8g,用jvisualvm查看,发现用char[]类型的数据占用了41%内存,同时另外一个com.alibaba.druid.stat.JdbcSqlStat类型的数据占用了35%的内存,也就是说整个堆中几乎全是这两类数据。如下图:

a

查看char[]类型数据,发现几乎全是sql语句。

b

接下来查看char[]的引用情况:

c

找到了JdbcSqlStat类,在代码中查看这个类的代码,关键代码如下:

构造函数只有这一个
public JdbcSqlStat(String sql){
    this.sql = sql;
    this.id = DruidDriver.createSqlStatId();
}

查看这个函数的调用情况,找到com.alibaba.druid.stat.JdbcDataSourceStat#createSqlStat方法:

public JdbcSqlStat createSqlStat(String sql) {
    lock.writeLock().lock();
    try {
        JdbcSqlStat sqlStat = sqlStatMap.get(sql);
        if (sqlStat == null) {
            sqlStat = new JdbcSqlStat(sql);
            sqlStat.setDbType(this.dbType);
            sqlStat.setName(this.name);
            sqlStatMap.put(sql, sqlStat);
        }

        return sqlStat;
    } finally {
        lock.writeLock().unlock();
    }
}

这里用了一个map来存放所有的sql语句。

其实到这里也就知道什么原因造成了这个问题,因为我们使用的数据源是阿里巴巴的druid,这个druid提供了一个sql语句监控功能,同时我们也开启了这个功能。只需要在配置文件中把这个功能关掉应该就能消除这个问题,事实也的确如此,关掉这个功能后到目前为止线上没再触发FullGC

d

其他

如果用mat工具查看,建议把 "Keep unreachable objects" 勾上,否则mat会把堆中不可达的对象去除掉,这样我们的分析也许会变得没有意义。如下图:Window-->References 。另外jvisualvm对ool的支持不是很好,如果需要oql建议使用mat。

image

目录
相关文章
|
2月前
|
存储 监控 Java
线上OOM排查
本文介绍了JDK工具的使用方法及其应用场景。首先详细说明了`jps`、`jstack`、`jstat`和`jmap`等工具的基本用法及参数含义,帮助开发者实时监控Java进程的状态,诊断线程问题及内存使用情况。接着介绍了`jvisualvm.exe`和`MemoryAnalyzer.exe`两款内存诊断工具,展示了如何通过这些工具进行内存分析。最后,文章提供了在线上OOM故障排查的具体步骤,并给出了解决方案示例,以便开发者更好地理解和解决实际问题。
线上OOM排查
|
3月前
|
监控 负载均衡 算法
线程数突增!领导说再这么写就GC掉我:深入理解与优化策略
【8月更文挑战第29天】在软件开发的世界里,性能优化总是开发者们绕不开的话题。特别是当面对“线程数突增”这样的紧急情况时,更是考验着我们的技术功底和问题解决能力。今天,我们就来深入探讨这一话题,分享一些工作学习中积累的技术干货,帮助大家避免被“GC”(垃圾回收,也常用来幽默地表示“被炒鱿鱼”)的尴尬。
47 2
|
4月前
|
Java BI 运维
开发与运维配置问题之升级机器配置后出现频繁的GC问题和超长的GC时间如何解决
开发与运维配置问题之升级机器配置后出现频繁的GC问题和超长的GC时间如何解决
35 1
|
3月前
|
监控 JavaScript Java
JVM源码级别分析G1发生FullGC元凶的是什么
线上系统遭遇频繁Old GC问题,监控显示出现多次“to-space exhausted”日志,这表明垃圾回收过程中因年轻代 Survivor 区或老年代空间不足导致对象晋升失败。通过 JVM 源码分析,此问题源于对象转移至老年代失败时,JVM 无法找到足够的空间存放存活对象。进一步排查发现大对象分配占用了预留空间,加剧了空间不足的情况。使用 JFR 分析工具定位到定期报表序列化导致大量大对象生成,通过改用堆外内存进行序列化输出,最终解决了频繁 Old GC 问题。
117 0
|
5月前
|
Arthas 监控 Java
线上频繁fullgc问题-SpringActuator的坑
偷偷开启的监控在吃内存
115 0
|
SQL canal 运维
JVM第六讲:线上环境 FGC 频繁,如何解决?
JVM第六讲:线上环境 FGC 频繁,如何解决?
293 0
|
Java 调度
CPU突然飙高系统反应慢,是怎么导致的?有什么办法排查?
面试过程中,场景类的问题更容易检测出一个开发人员的基本能力。这不,有一位小伙伴去阿里面试,第一面就遇到了关于“CPU 飙高系统反应慢怎么排查”的问题?当时这位小伙伴不知从何下手。 今天,我给大家分享一下我的解决思路。
174 0
|
缓存 监控 算法
因Full GC导致CPU飙升到100%问题排查记录
因Full GC导致CPU飙升到100%问题排查记录
339 0
|
算法 Java 数据处理
OOM和频繁GC预防方案
这段代码明明很简单,日常跑的都没问题,怎么一大促就卡死甚至进程挂掉?大多是因为设计时,就没针对高并发、高吞吐量case考虑过内存管理。
380 0
|
负载均衡 算法 Java
记一次线上频繁FGC的事件和解决方式
1.大量的请求,调用的地方要注意是否会导致内存的大量消耗,尽可能使用池化技术,单例等,减少创建,销毁的系统开销;2.CMS 的几个缺点,可以参考《深入java虚拟机》,对CPU占用会比较高,无法处理浮动垃圾,还有就是CMS使用的是标记-清除算法,会导致大量的空间碎片,碎片过多的话,导致分配大对象很困难,所以不得不进行FGC,也可能是这个原因导致了本文说的一直FGC的问题。
391 0
记一次线上频繁FGC的事件和解决方式