记录一次JdbcDataSourceStat导致内存泄露问题
问题现象
线上有一台服务是运行一些初始化数据操作的,操作时会运行大量的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语句
问题分析
首先查看源码,了解一下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 许可协议。转载请注明来自
陆壹笔记!
喜欢就支持一下吧