问题现象

线上有一台服务是运行一些初始化数据操作的,操作时会运行大量的SQL脚本,运行一段时间后就会出现OOM问题,触发监控报警

调试分析

生成堆内存快照

jmap -dump:live,file=heapdump.hprof 14039

使用Eclipse Memory Analyzer (MAT)或者 JProfiler分析

从下边看到DruidDataStat占用90%,com.alibaba.druid.stat.JdbcDataSourceStat$1对象里面有个LinkedHashMap,这里每个Entry占用了70多M内存,里面存储的都是一些SQL语句

2025-02-13-jmrwdfdp.png

问题分析

首先查看源码,了解一下sqlStatMap是如何生成的。打开com.alibaba.druid.stat.JdbcDataSourceStat文件。如下

    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();
        }
    }

Druid 开启了 stat 监控(有个web页面可以查看sql的历史执行记录),部分 SQL 语句会被存储在 sqlStatMap 中,导致内存占用增加。如果不手动处理这个 map,其中的引用会一直被持有,导致 GC 无法回收,从而引发内存泄漏问题。

解决方案

可以通过配置关闭这个监控,因为平时也不使用。数据库已经迁移到云上,云服务提供商也可以查看 SQL 监控。找到druid.filters配置,下边是修改前的配置

    druid:
      filters: slf4j,stat

修改后配置如下:

    druid:
      filters: slf4j

网上也查到一些类似的问题

最后重新部署项目后,关闭监控并进行测试观察。确保内存占用保持稳定,同时检查JdbcDataSourceStat,也没有大对象占用引用。

文章作者: 陆壹
版权声明: 本站所有文章除特别声明外,均采用 CC BY-NC-SA 4.0 许可协议。转载请注明来自 陆壹笔记
Java java jvm druid
喜欢就支持一下吧