JdbcRowSet中的内存泄漏

时间:2013-09-12 13:49:31

标签: java mysql jdbc memory-leaks rowset

我尝试使用大表(大约一万条记录)中的记录填充JdbcRowSet。我尝试了两种变体(见下面的代码):

  1. 创建连接对象,使用JdbcRowSetImpl(连接)实例化,循环执行查询。
  2. 使用JdbcRowSetImpl(DriverManager.getConnection(“jdbc:....”)实例化,循环执行查询。
  3. 第一个变体导致内存泄漏,直到堆满。第二个变体没有内存泄漏。有人可以解释为什么第一个在重用连接对象时会导致内存泄漏吗?

    感谢

    代码为1。

    import java.sql.Connection;
    import java.sql.DriverManager;
    import java.sql.SQLException;
    import javax.sql.rowset.JdbcRowSet;
    import com.sun.rowset.JdbcRowSetImpl;
    
    public class JdbcRowSetMemoryLeak {
    
    /**
     * @param args
     */
    public static void main(String[] args) {
        String username = "user";
        String password = "password";
        Connection connection = null;
        try {
            Class.forName("com.mysql.jdbc.Driver");
            connection = DriverManager.getConnection("jdbc:mysql://localhost/db_ams?user=" + username + "&password=" + password);
        } catch (ClassNotFoundException | SQLException e) {
            e.printStackTrace();
        }
        JdbcRowSet jdbcRS = null;
        for (int i=0;i<150;i++){
            System.out.println(i);
            try {
                jdbcRS = new JdbcRowSetImpl(connection); // <-- Memory is leaking
                jdbcRS.setCommand("Select * from sample_t;");
                jdbcRS.execute();
    //              jdbcRS.close(); <-- Returns a null pointer Exception
                jdbcRS = null;
            } catch (SQLException e) {
                e.printStackTrace();
            }
            try {
                Thread.sleep(1000);
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
        }
    
    }
    
    }
    

    代码为2。

    import java.sql.DriverManager;
    import java.sql.SQLException;
    import javax.sql.rowset.JdbcRowSet;
    import com.sun.rowset.JdbcRowSetImpl;
    
    public class JdbcRowSetMemoryGood {
    
    /**
     * @param args
     */
    public static void main(String[] args) {
        String username = "user";
        String password = "password";
        try {
            Class.forName("com.mysql.jdbc.Driver");
        } catch (ClassNotFoundException e) {
            e.printStackTrace();
        }
        JdbcRowSet jdbcRS = null;
        for (int i=0;i<150;i++){
            System.out.println(i);
            try {
                jdbcRS = new JdbcRowSetImpl(DriverManager.getConnection("jdbc:mysql://localhost/db_ams?user=" + username + "&password=" + password));
                jdbcRS.setCommand("Select * from sample_t;");
                jdbcRS.execute();
                jdbcRS.close();
                jdbcRS = null;
            } catch (SQLException e) {
                e.printStackTrace();
            }
            try {
                Thread.sleep(1000);
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
        }
    
    }
    
    }
    

1 个答案:

答案 0 :(得分:0)

您的问题的答案 '为什么第一个在重用连接对象时导致内存泄漏?'

是的,您正在重用连接对象,但是您在每次迭代中都创建了一个新的JdbcRowSet对象,并且不关闭它会导致内存泄漏。 jdbcRS = null;不会关闭资源。

您的问题的答案 '为什么我不能在第一个snippset中关闭ResultSet但在第二个?

在您的第一个代码段中,当您使用关闭方法JdbcRowSet关闭jdbcRS对象jdbcRS.close();时,您也会关闭连接。因此,第二次迭代将抛出NullPointerException,因为在jdbcRS = new JdbcRowSetImpl(connection); connection已经关闭。

第二个代码段工作正常,因为您在每次迭代中都创建了一个新连接 在getConnection方法中。

如果您在每次迭代后自动使用CachedRowSet来关闭资源,那就最好了:

package databases;
import java.sql.SQLException;
import javax.sql.rowset.*;

public class CachedRowSet_Usage {

    public static void main(String[] args) {
        String username = "username";
        String password = "password";
        String url = "jdbc:mysql://localhost:3306/your_database_name"; 

        try{
            CachedRowSet rs = RowSetProvider.newFactory().createCachedRowSet();
            //JdbcRowSet rs = RowSetProvider.newFactory().createJdbcRowSet();
            rs.setUrl(url);
            rs.setUsername(username);
            rs.setPassword(password);

            for(int i=0;i<150;i++){
                System.out.println(i);
                rs.setCommand("Select * from your_table");
                rs.execute();  
                //rs.close();  <-- no use, rs closes automatically
            }
        }
        catch (SQLException e) {
            e.printStackTrace();
        }
    }
}