4

我们在 JBoss 6.1 的 JDBC 池中发现了一个非常严重的泄漏。

这是由于代码依赖于close连接上的方法来关闭底层语句。

尽管WrappedConnection确实关闭了它们,但代码如下所示

if (statements != null) {
  for (Iterator
       <Map.Entry<WrappedStatement, Throwable>> i=statements.entrySet().iterator(); 
       i.hasNext(); )
  {
     Map.Entry<WrappedStatement, Throwable> entry = i.next(); 
     WrappedStatement ws= entry.getKey();
     if (trackStatements==BaseWrapperManagedConnectionFactory.TRACK_STATEMENTS_TRUE_INT)
     {
       Throwable stackTrace = entry.getValue();
       log.warn("Closing a statement you left open, please do your own housekeeping",
                 stackTrace);
     }
     try
     {
       ws.internalClose();
     }
     catch (Throwable t)
     {
       log.warn("Exception trying to close statement:", t);
     }
   }
 }

statements 对象永远不会从其映射中删除语句,并且映射不断增长,并且这些语句保存结果集等(至少在我正在使用的 JDBC 驱动程序中)。

我想知道是否有人曾经用比这更强大的替代实现替换了 JBoss 中的 jdbc 池?


作为对此的一个小补充,代码和行为与结果集相同(基本上是复制和粘贴),尽管如果您不坚持任何时间长度的语句,内存泄漏可能并不严重(不像连接,按设计存在于池中)。

4

2 回答 2

4

未能关闭底层语句不是 JBOSS 池泄漏。我相信责任在于您的数据库供应商的 JDBC 驱动程序实现。如果我没记错的话,众所周知,当连接关闭时,Oracle 的驱动程序并没有关闭底层资源(至少在 2006 年是这样)。不知道有没有改正。

http://www.theserverside.com/discussions/thread.tss?thread_id=41036

责任永远是你的。

建议您关闭 finally 块中的所有 ResultSet 和 Statement 实例,分别包装在 try/catch 块中,以与创建相反的顺序。

如果这是正确的,并且您同意,那么更改池实施是不够的。您必须检查您的代码并自己完成。如果您很聪明并且设计在一个干净的持久层中,那么它应该相对容易。

很抱歉没有早点阅读您的代码。我不知道你为什么要Statement输入一个Map,尤其是一个不是WeakHashMap. Statement我的建议是将所有ResultSet实例紧密绑定在持久层内。在方法范围内创建和关闭它们;没有缓存。

如果你要分析代码,我想你会发现这里没有任何节省。这些类都不是线程安全的,所以挂在它们上面可能会导致一些相当讨厌的错误。您的应用程序也将更具可扩展性。

于 2012-05-15T23:18:11.130 回答
2

JBoss 将其用于数据源的连接池部署为资源适配器 RAR。默认情况下,有两个可用jboss-local-jdbc.rarjboss-xa-jdbc.rarindeploy文件夹。要使用的连接工厂和包装器在META-INF/ra.xml

因此,选择是根据您声明的数据源替换这些资源适配器中的一个或两个。但是实现必须支持资源征募到与 JTS 的事务以及安全检查。

不是那么容易的工作,你可能会是第一个这样做的人。

于 2012-06-11T14:48:22.190 回答