【问题标题】:simple mysql/jdbc code causing a memory leak?导致内存泄漏的简单 mysql/jdbc 代码?
【发布时间】:2018-01-11 07:08:51
【问题描述】:

我第一次尝试分析堆转储以查找内存泄漏。我正在使用 MAT 打开堆转储,并且很明显它是一个对象?这几乎占据了整个堆,它是一个 sql 类 com.mysql.cj.jdbc.ConnectionImpl。

由于 sql 真的只在我的代码的一部分中使用,它基本上必须是这里的一小段代码......

static Connection getDBconn() {
    Connection conn = null;
    while (conn == null) {
        try {
            conn = DriverManager.getConnection(serverURL, user, pass);
        } catch (SQLException e) {
            Logger.logError(e);
        }
    }
    return conn;
}
static void update(String sql) {
    while (currConn == null)
        currConn = getDBconn();
    boolean error = false;
    do {
        try {
            currConn.createStatement().executeUpdate(sql);
        } catch (SQLException e) {
            try {
                currConn.close();
            } catch (SQLException e1) {
                Logger.logError(e1);
            }
            currConn = getDBconn();
            Logger.logError(e);
            error = true;
        }
    } while (error);
}
static ResultSet query(String sql) {
    while (currConn == null)
        currConn = getDBconn();
    ResultSet rs = null;
    while (rs == null) {
        try {
            rs = currConn.createStatement().executeQuery(sql);
        } catch (SQLException e) {
            try {
                currConn.close();
            } catch (SQLException e1) {
                Logger.logError(e1);
            }
            currConn = getDBconn();
            Logger.logError(e);
        }
    }
    return rs;
}

这段代码应该做的基本上是将查询/更新语句包装在一些方法中,以确保每个命令始终最终执行,即使出现错误也是如此。我的程序将运行很长时间,有很多请求,我想确保它自动处理所有可能的问题,而不会中断程序。

我所写的内容将工作大约一个小时左右,然后即使我将堆设置为 8gb,我也会收到内存不足错误,这显然是矫枉过正。我还应该注意我没有收到任何 sql 错误,所以它甚至没有进入 catch 块。显然,此代码存在某种泄漏,但我无法弄清楚它可能是什么。任何建议都将不胜感激,如果需要,我可以提供有关堆转储的更多信息。

【问题讨论】:

  • 确保在不再需要时关闭所有数据库资源(连接、语句、结果集)。尝试使用资源最容易做到这一点。
  • @Henry 所以我想为每个单独的数据库查询/更新执行此操作?
  • 您可以为多个请求重用相同的连接,但必须关闭语句和结果集。连接也必须最终关闭。
  • @Henry 好的,谢谢,我的程序应该无限期运行,有没有办法知道何时必须关闭连接,为每个请求继续创建一个新的连接是否昂贵?
  • 创建连接的成本相对较高,因此重用它是有意义的。当连接不再工作时(例如由于故障或网络问题),可能需要关闭连接。

标签: java jdbc heap-dump


【解决方案1】:

当您不需要两次时,您正在获得连接

 try {
            currConn.close();
        } catch (SQLException e1) {
            Logger.logError(e1);
        }
 -->   currConn = getDBconn();
        Logger.logError(e);

只需在currConn.close(); 之后删除currConn = getDBconn(),就不会出现连接泄漏。

更好的是,即使没有发生错误,也要在 finally 上关闭连接:

    try {
        rs = currConn.createStatement().executeQuery(sql);
    } catch (SQLException e) {
        Logger.logError(e);
    finally{
        try {
            currConn.close();
        } catch (SQLException e1) {
             Logger.logError(e1);
        }
    }

还要创建一个方法来防止代码重复和关闭连接的不同实现。

【讨论】:

    猜你喜欢
    • 2015-01-24
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2012-01-18
    • 1970-01-01
    • 2019-08-26
    相关资源
    最近更新 更多