我尝试使用大表(大约一万条记录)中的记录填充JdbcRowSet。我尝试了两种变体(见下面的代码):
第一个变体导致内存泄漏,直到堆满。第二个变体没有内存泄漏。有人可以解释为什么第一个在重用连接对象时会导致内存泄漏吗?
感谢
代码为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();
}
}
}
}
答案 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();
}
}
}