【问题标题】:Java SQL memory leakJava SQL 内存泄漏
【发布时间】:2022-01-24 19:47:28
【问题描述】:

我遇到了一个问题,我在服务器上运行了一个 java 应用程序,它开始在内存中增长,直到最终服务器无法再处理它。

这是某种内存泄漏/资源泄漏问题,由于垃圾收集,我认为这在 Java 中极为罕见。我猜有些东西被引用但从未使用过,所以垃圾收集器不会收集它。

问题是内存中的大小增长非常缓慢,以至于我无法正确调试它(可能需要两周时间才能使服务器无法使用)。 我使用的是java + mysql-connector,我确定内存泄漏是由与数据库连接相关的东西引起的。

这是我连接到数据库的方式:

 private static Connection connect(){
    try {
        Connection conn = null;
        conn =  DriverManager.getConnection("jdbc:mysql://localhost:3306/database","client","password");
        return conn;
    }catch(SQLException ex){
        System.out.println("SQLException: " + ex.getMessage());
        System.out.println("SQLState: " + ex.getSQLState());
        System.out.println("VendorError: " + ex.getErrorCode());
        return null;
    }
}
public static Connection getConnection(){
    try {
        if (connection == null || connection.isClosed()) connection = connect();
        return connection;

    }catch (SQLException exception){
        System.out.println("exception trying to connect to the database");
        return null;
    }
}

我在这里找不到任何可能的问题,但谁知道呢!

以下是我从数据库中检索信息的方式:

 public void addPoints(long userId,int cantidad){
    try {
        if(DatabaseConnector.getConnection()!=null) {
            PreparedStatement stm = DatabaseConnector.getConnection().prepareStatement("UPDATE users SET points = points + ? WHERE id = ? ");
            stm.setLong(2, userId);
            stm.setInt(1, cantidad);
            if(stm.executeUpdate()==0){ //user doesn't have any point records in the database yet
                PreparedStatement stm2 = DatabaseConnector.getConnection().prepareStatement("INSERT INTO users (id,points) VALUES (?,?)");
                stm2.setLong(1, userId);
                stm2.setInt(2, cantidad);
                stm2.executeUpdate();
            }
        }
    }catch (SQLException exception){
        System.out.println("error recording points");
    }
}

 public ArrayList<CustomCommand> getCommands(long chatId) throws SQLException{
    ArrayList<CustomCommand> commands = new ArrayList<>();
    if(DatabaseConnector.getConnection() != null) {
        PreparedStatement stm = DatabaseConnector.getConnection().prepareStatement("SELECT text,fileID,commandText,type,probability FROM customcommands WHERE chatid = ?");
        stm.setLong(1, chatId);
        ResultSet results = stm.executeQuery();
        if(!results.isBeforeFirst()) return null;
        while (results.next()){
            commands.add(new CustomCommand(results.getString(1),results.getString(2),results.getString(3), CustomCommand.Type.valueOf(results.getString(4)),results.getInt(5)));
        }
        return commands;
    }
    return null;
}

也许问题与异常捕获和语句未正确执行有关?也许与结果集有关? 这让我疯狂。谢谢你帮助我!

【问题讨论】:

  • 请看一下如何使用try with resources正确关闭JDBC资源。您还在每个方法开始时的空值检查中创建并丢弃了一个 Connection,这是不必要的。

标签: java mysql sql jdbc memory-leaks


【解决方案1】:

在返回之前,您无需清理 ResultSetStatement。这是个坏主意。您应该在 finally 块中的单独 try/catch 块中关闭每个。

ResultSet 是表示数据库上的数据库游标的对象。您应该关闭它,以免游标用完。

我不会有一个静态Connection。我希望有一个线程安全的托管连接池。

我不会返回空值。您不清楚用户应该对此做什么。最好抛出异常。

【讨论】:

  • 这只是一个电报机器人,所以我自己处理错误,这不是一个大项目,这就是为什么我没有创建异常并且只有一个静态连接。非常感谢您的帮助,我已经更改了在 finally 块中或返回后关闭每个语句/结果集的代码。如果可行,我将返回此处并将状态更改为已解决:)
  • 不,您必须在创建它们的方法范围内的 finally 块中关闭它们。每个都必须包装在单独的 try/catch 块中,以便两者都完成。即使抛出异常也必须关闭它们。
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 2016-09-29
  • 2015-08-14
  • 2012-08-11
  • 2015-12-14
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多