【发布时间】:2011-09-14 23:43:38
【问题描述】:
我正在使用 Sun JVM 在 Glassfish 上运行一个应用程序。我们的一位开发人员进行了一项看似无害的更改,但似乎对系统造成了严重破坏。他所做的只是将现有的工厂方法调用与另一个封装起来以提供一些日志记录,如下所示:
// Old code
PreparedStatement stmt = connection.prepareStatement(sql);
// New code
PreparedStatement stmt = StatementLogger.prepareStatement(connection, sql);
class StatementLogger {
static PreparedStatement prepareStatement(Connection connection, String sql) {
logger.info("Preparing SQL: " + sql);
return connection.prepareStatement(sql);
}
}
由于更改,PreparedStatement 的生命周期似乎比以前长得多。在这两种情况下,语句的结束方式完全相同。但是随着更改,我们的数据库连接用完了。
当然,对声明的实时引用在新版本中的存活时间会稍微长一些。这可能会使其在次要垃圾收集中幸存下来的机会稍好一些。但对我来说,差异似乎微不足道。 (弹出一帧。)垃圾回收中是否有其他东西可以让它在第一种情况下将语句识别为短期对象,但在第二种情况下将其识别为长期存在?
这里会发生什么?
【问题讨论】:
-
为什么还要依赖GC来关闭连接?
-
通常你应该在使用后关闭你的语句。
-
我确实在这两种情况下都关闭了语句。但显然这并没有完全发表声明。因为如前所述,这种看似微不足道的变化会导致语句在第二种情况下徘徊并占用连接。如果我们将服务器单独放置一段时间,它似乎确实会清理其中的一些,所以我假设涉及到 GC。
-
疯狂猜测:调用 connection.prepareStatement(sql) 可以被视为对语句的匿名引用,而在静态环境中可能会以某种方式困难的 GC 工作。尝试将 connection.prepareStatment 结果分配给一个变量,然后返回该变量。
-
语句和连接都必须关闭。一旦连接关闭,它就会再次可用,与对象的生命周期无关。
标签: java garbage-collection jvm