我正在使用与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%)
我没有明确关闭我的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(); }
}
文档说该语句将在关闭时关闭相关的ResultSet实例 - 这个ubuntu机器上的jdbc实现是否可能实际上没有这样做?我没有对我的代码(一个打包的.war文件)进行任何更改,我只是把它放到这个ubuntu机器上的一个jetty实例中。
分析显示那些com.mysql.jdbc.ConnectionPropertiesImpl实例继续增长,所以猜测这可能是正在发生的事情。
我只是想在我离开之前检查并修改我的所有代码以显式关闭ResultSet实例。看看MySql Workbench,我在Client Connections视图中看不到任何异常 - 我的应用程序连接进来并且似乎已经清理好了。
由于
--------------------更新--------------------
我已经更改了所有ResultSet实例,以便立即关闭它们以及finally {}块,就像我的Connection和PreparedStatement实例一样。这似乎并没有帮助,记忆力不断增长。
更多地了解一下,我注意到了这个课程:
com.mysql.jdbc.JDBC4Connection
并且实例数量永远不会减少。大约10分钟的运行时间后,我看到几乎5k个实例(呀?)。
这篇文章与我遇到的内容非常相似:
Memory leak in 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;
}
}
使用它:
protected void doGet(HttpServletRequest request,
HttpServletResponse response)
{
Connection conn = null;
try {
conn = DsHelper.get().getDataSource();
...
}
finally {
if (conn != null) { conn.close(); }
}
}
答案 0 :(得分:2)
ResultSet泄漏是众所周知的常见问题。明确地关闭它们是一个非常好的主意,并且值得你努力做的每一点麻烦。去这样做!严重。
不同的VM实现以不同方式处理垃圾收集。这可能就是你在新环境中看到东西堆积的原因。
在Oracle上,ResultSet对象是稀缺服务器资源(游标)的反映,如果不明确关闭它们,最终服务器用完,其他连接的工作开始失败。
去干净吧!
答案 1 :(得分:1)
基于Statement javadoc,不需要显式关闭ResultSet。
注意:当Statement对象关闭时,它的当前ResultSet对象, 如果存在,也会关闭。
但我建议在完成任务后立即关闭ResultSet。即使在关闭连接之后,Oracle的Statement实现也存在打开游标的问题。因此,有可能出现“超出最大打开游标数”等异常。
您可以使用java 1.7中引入的最新功能避免显式关闭Statement。 更好的&更清洁的代码(如果您使用的是Java 1.7 +)
public static void viewTable(Connection con) throws SQLException {
String query = "select COF_NAME, SUP_ID, PRICE, SALES, TOTAL from COFFEES";
try (Statement stmt = con.createStatement()) {
ResultSet rs = stmt.executeQuery(query);
while (rs.next()) {
String coffeeName = rs.getString("COF_NAME");
int supplierID = rs.getInt("SUP_ID");
float price = rs.getFloat("PRICE");
int sales = rs.getInt("SALES");
int total = rs.getInt("TOTAL");
System.out.println(coffeeName + ", " + supplierID + ", " +
price + ", " + sales + ", " + total);
}
} catch (SQLException e) {
JDBCTutorialUtilities.printSQLException(e);
}
}
观察try块语法的不同,观察没有明确的close方法调用。在内部照顾它。参考 - try-with-resources Statement