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

use*_*425 6 java mysql jdbc 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%)
Run Code Online (Sandbox Code Playgroud)

我没有明确关闭我的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(); }
}
Run Code Online (Sandbox Code Playgroud)

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

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

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

谢谢

--------------------更新--------------------

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

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

com.mysql.jdbc.JDBC4Connection
Run Code Online (Sandbox Code Playgroud)

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

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

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;
    }
}
Run Code Online (Sandbox Code Playgroud)

使用它:

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

O. *_*nes 2

结果集泄漏是众所周知的常见现象。明确地关闭它们确实是一个好主意,并且值得您付出一切努力来努力做到这一点。去这样做!严重地。

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

在 Oracle 上,ResultSet 对象是稀缺服务器资源(游标)的反映,如果您不显式关闭它们,最终您的服务器会耗尽并且其他连接的工作开始失败。

去清理它们吧!