New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
每个sql语句都会长期持有引用,加快FullGC频率 #1664
Comments
楼主这个问题最终是如何解决的啊 |
@fuyi-wang 我们当初开启了这个功能,但没有使用。找到原因后,就把这个功能给关闭了。线上就正常了。 如果需要使用这个功能的话,可以参考:https://github.com/alibaba/druid/wiki/%E5%B8%B8%E8%A7%81%E9%97%AE%E9%A2%98 |
@rocky-peng 我遇到的问题和你的一样,但又想使用 SQL监控的功能,我再查查看有没有其他的解决方案,多谢哈 |
楼主,我是JdbcDataSourceStat类中属性 |
一样的情况,springboot项目,运行一天就oom了 |
@xuexuegege 试试自己写工厂方法new出datasurce,new的时候应该有参数设置 |
看了下,springboot集成druid是自动配置的,看了一下源码发现 @Bean
@ConfigurationProperties("spring.datasource.druid.filter.stat")
@ConditionalOnProperty(
prefix = "spring.datasource.druid.filter.stat",
name = {"enabled"},
matchIfMissing = true
)
@ConditionalOnMissingBean
public StatFilter statFilter() {
return new StatFilter();
} matchIfMissing = true 这里默认开启了,所以需要手动设置为false就行了 spring.datasource.druid.filter.stat.enabled=false |
其实有的业务需要监控,但是这里根据情况可以打开SQL合并, String property = properties.getProperty("druid.stat.mergeSql");
if ("true".equals(property)) {
this.mergeSql = true;
} else if ("false".equals(property)) {
this.mergeSql = false;
} 这里SQL合并源码有点复杂,大致意思是简化sql语句, JdbcSqlStat sqlStat = (JdbcSqlStat)this.sqlStatMap.get(sql);
if (sqlStat == null) {
sqlStat = new JdbcSqlStat(sql);
sqlStat.setDbType(this.dbType);
sqlStat.setName(this.name);
this.sqlStatMap.put(sql, sqlStat);
} 这样就会大大减少这么map的大小。 if (connectProperties != null) {
Object arg = connectProperties.get("druid.stat.sql.MaxSize");
if (arg == null) {
arg = System.getProperty("druid.stat.sql.MaxSize");
}
if (arg != null) {
try {
this.maxSqlSize = Integer.parseInt(arg.toString());
} catch (NumberFormatException var7) {
LOG.error("maxSize parse error", var7);
}
}
} 因为这里重写了弃老规则,所以put的时候会判断下是否大于最大,是的话就会弃老 this.sqlStatMap = new LinkedHashMap<String, JdbcSqlStat>(16, 0.75F, false) {
protected boolean removeEldestEntry(java.util.Map.Entry<String, JdbcSqlStat> eldest) {
boolean remove = this.size() > JdbcDataSourceStat.this.maxSqlSize;
if (remove) {
JdbcSqlStat sqlStat = (JdbcSqlStat)eldest.getValue();
if (sqlStat.getRunningCount() > 0L || sqlStat.getExecuteCount() > 0L) {
JdbcDataSourceStat.this.skipSqlCount.incrementAndGet();
}
}
return remove;
}
}; |
@xuexuegege nice |
nice, got it |
顶一个 |
|
timeBetweenLogStatsMillis 设置这个属性可以解决 |
mark一下 |
可以利用启动将缓存的条数调小,比如只保存3条 |
发现fullgc频繁,执行dump操作,发现近45%的内存占用都是存储的sql语句(堆的设置是2G)。跟踪引用关系,找到了JdbcSqlStat类,接着找到JdbcDataSourceStat类,发现如下代码发现是在这持有了sql语句的引用:
进一步排查代码,暂时只发现三个方法对sqlStatMap对象存在移除操作:
第二个reset方法,发现是通过前端指定的url来触发执行(我们这里的情况是没有调用这个url的)
第三个getSqlStatMapAndReset,发现是在通过注册了一个ServletContextListener来添加了一个定时任务,没隔300second来触发(因为我们这里的应用不是一个web所以也没有触发这个操作)
第一个setMaxSqlSize方法调用关系太多,也就没有一一梳理,不知道这个方法的调用策略是怎样的呢?
The text was updated successfully, but these errors were encountered: