数据源的Java内存泄漏
我多次听说,不关闭数据库连接可能会导致内存泄漏数据源的Java内存泄漏,java,memory-leaks,jvm,datasource,Java,Memory Leaks,Jvm,Datasource,我多次听说,不关闭数据库连接可能会导致内存泄漏 (例如本节) 我试图通过从org.apache.commons.dbcp2.BasicDataSource获取连接来重现同样的问题 而不是关闭它 这是我的代码: //Repo class private final BasicDataSource ds; public Repo() { ds = new BasicDataSource(); ds.setDriverClassName("org.postgresql.Dr
(例如本节) 我试图通过从org.apache.commons.dbcp2.BasicDataSource获取连接来重现同样的问题 而不是关闭它 这是我的代码:
//Repo class
private final BasicDataSource ds;
public Repo() {
ds = new BasicDataSource();
ds.setDriverClassName("org.postgresql.Driver");
ds.setUrl("jdbc:postgresql://localhost/postgres");
ds.setUsername("postgres");
ds.setPassword("postgres");
ds.setMaxOpenPreparedStatements(10000);
ds.setMaxTotal(10000);
}
public PreparedStatement prepStatement(String sql) throws SQLException {
return this.ds.getConnection().prepareStatement(sql);
}
//Logic class
public JsonNode logic(String name) {
PreparedStatement ps = this.repo.prepStatement("select data from public.users where name = ? ");
ps.setString(1, name);
//The rest of the logic - no close method or try with resource
}
我已经重复了差不多400次相同的过程,并且减小了初始堆大小和最大堆大小。不过,没有内存泄漏的迹象。即使在VisualVM监控中,堆图也很正常:
关于如何重现这个问题有什么想法吗?不关闭资源的问题不是潜在的内存泄漏,而是潜在的资源泄漏。我们讨论的是文件句柄、网络连接,但甚至是可能在数据库服务器端分配的资源,在JVM中根本不可见 实际的
PreparedStatement
实现是否具有终结器或清理器之类的保护措施,当对象被垃圾收集时,它们将关闭资源,这取决于特定的数据库驱动程序。但是,即使有,这也意味着资源将被保留,直到后续的垃圾收集周期识别出无法访问的对象并触发终结
在您的特定设置中,似乎每分钟都有一次垃圾收集。也许,关键的非内存资源在这些点上得到了清理;你甚至都没有检查它们
但是,即使已为此设置清理了这些资源,您也必须注意以下几点:
- 并非每个数据库驱动程序都可以这样工作
- 在实际的生产环境中,持有关键的非内存资源(如锁、文件句柄、数据库连接等)的时间比需要的时间长一分钟,这已经是一个巨大的问题
- 不能保证你每分钟都有一次垃圾收集。一个系统可以在没有垃圾收集的情况下运行数小时甚至数天
- 无法保证垃圾收集能够识别特定的不可访问对象。在一个简单的设置中,当下一次收集发生时,对象属于年轻一代,这可能会顺利工作,但现代并发收集器乐于在短时间内回收大量内存,并且可以配置时间限制,而不急于收集每个对象
就记忆而言,每个物体的记忆都是相等的,因此,它是不相关的,哪些物体被这种“雄鹿的最大爆炸”收藏忽略了。因此,
实例可能是每个集合中被忽略的不幸的不可访问对象之一。这与几个字节无关,它会阻塞,这就是为什么这种策略是允许的。如前所述,问题在于它可能无限期地保留非内存资源PreparedStatement
\“…name=”+name+“\''”
我试图通过不关闭连接来故意创建内存泄漏。