如果没有明确关闭,ResultSet会泄漏吗?

我正在使用带有jetty的jdbc连接池,在服务器实例上进行了这种设置,一年多没有问题。 我已经切换到新的ubuntu服务器,并且内存不足。 我正在分析内存使用情况并查看以下顶级实例:

java.util.Hashtable$Entry (33%) com.mysql.jdbc.ConnectionPropertiesImpl$BooleanConnectionProperty (13%) com.mysql.jdbc.ConnectionPropertiesImpl$StringConnectionProperty (3%) com.mysql.jdbc.ConnectionPropertiesImpl$IntegerConnectionProperty (3%) 

我没有显式关闭我的ResultSet实例,我正在做类似的事情:

 Connection conn = null; PreparedStatement stmt = null; try { conn = ...; stmt = ...; ResultSet rs = ...; rs.useIt(); } finally { if (stmt != null) { stmt.close(); } if (conn != null) { conn.close(); } } 

文档说,Statement将在关闭时关闭相关的ResultSet实例 – 这个ubuntu机器上的jdbc实现是否可能实际上没有这样做? 我没有对我的代码(一个打包的.war文件)进行任何更改,我只是把它放到这个ubuntu机器上的一个jetty实例中。

分析显示那些com.mysql.jdbc.ConnectionPropertiesImpl实例继续增长,所以猜测这可能是正在发生的事情。

我只是想在我离开之前检查并修改我的所有代码以显式关闭ResultSet实例。 看看MySql Workbench,我在Client Connections视图中看不到任何exception – 我的应用程序连接进来并且似乎已经清理好了。

谢谢

——————–更新——————–

我已经更改了所有ResultSet实例,以便立即关闭它们以及finally {}块,就像我的Connection和PreparedStatement实例一样。 这似乎没有帮助,但内存不断增长。

再看一些,我注意到了这个课程:

 com.mysql.jdbc.JDBC4Connection 

并且实例数量永远不会减少。 大约10分钟的运行时间后,我看到几乎5k个实例(呀?)。

这篇文章看起来与我遇到的非常相似:

JDBC4Connection中的内存泄漏

OP最后说:

ORM依赖于在终结器中关闭与空闲资源的连接(有时会关闭结果集和语句),但是池保持连接打开几个小时,如果出现任何峰值,这会导致OOM。

我不明白这意味着什么,或者如何解决这个问题。 我很确定我现在到处都在关闭我的资源(否则当我在我的其他Windows服务器上运行相同的webapp时,我也可能在那里看到了泄漏?)。

——————–更新——————–

仍然看到相同的行为,这是我在我处理的每个请求中打开数据库连接的方式(省略错误检查):

  public class DsHelper { private static DsHelper sInstance; private DataSource mDs; public DsHelper() { InitialContext ctx = new InitialContext(); mDs = (DataSource)ctx.lookup("java:comp/env/jdbc/myds"); } public static DsHelper get() { if (sInstance == null) { sInstance = new DsHelper(); } return mInstance; } public DataSource getDataSource() { return mDs; } } 

使用它:

 protected void doGet(HttpServletRequest request, HttpServletResponse response) { Connection conn = null; try { conn = DsHelper.get().getDataSource(); ... } finally { if (conn != null) { conn.close(); } } } 

ResultSet泄漏是众所周知的常见问题。 明确地关闭它们是一个非常好的主意,并且值得你努力做到的每一点麻烦。 去这样做! 认真。

不同的VM实现不同地处理垃圾收集。 这可能就是你在新环境中看到东西堆积的原因。

在Oracle上,ResultSet对象是稀缺服务器资源(游标)的反映,如果不明确地关闭它们,最终服务器用完,其他连接的工作开始失败。

去干净吧!

基于Statement javadoc,不需要显式关闭ResultSet。

从javadocs页面 ,

注意:关闭Statement对象时,其当前ResultSet对象(如果存在)也将关闭。

但我建议在完成任务后立即关闭ResultSet。 即使在关闭连接之后,Oracle的Statement实现也存在打开游标的问题。 因此,有可能出现“超出最大打开游标数”等exception。

您可以使用java 1.7中引入的最新function避免显式关闭Statement。 更好更清洁的代码(如果您使用的是Java 1.7+)

 public static void viewTable(Connection con) throws SQLException { String query = "select COF_NAME, SUP_ID, PRICE, SALES, TOTAL from COFFEES"; try (Statement stmt = con.createStatement()) { ResultSet rs = stmt.executeQuery(query); while (rs.next()) { String coffeeName = rs.getString("COF_NAME"); int supplierID = rs.getInt("SUP_ID"); float price = rs.getFloat("PRICE"); int sales = rs.getInt("SALES"); int total = rs.getInt("TOTAL"); System.out.println(coffeeName + ", " + supplierID + ", " + price + ", " + sales + ", " + total); } } catch (SQLException e) { JDBCTutorialUtilities.printSQLException(e); } } 

观察try块语法的不同,观察没有明确的close方法调用。 在内部照顾它。 参考 – 尝试资源声明