终结者比你想象的还要邪恶

发布者    |      

Developerworks 推出了我读过的关于Java性能的最佳文章。作者们驳斥了在Java中创建临时对象是昂贵的这种说法,通过解释如何在Sun JVM中工作代际垃圾回收(这比典型的解释要详细一些)。好吧,我早就知道了;Hibernate从一开始就拒绝了对对象池的概念(不幸的是,EJB规范还没有跟上)。

我不知道的是,实现finalize()的对象需要两个完整的垃圾回收周期才能释放。我们都知道不能依赖finalize(),我们不应该在终结器中编写《重要》的代码。但是/这个/ finalize()方法,来自Hibernate的SessionImpl类,看起来是一个非常不错的想法

/**
 * Just in case user forgot to call close()
 */
protected void finalize() throws Throwable {
  
  log.debug("running Session.finalize()");
  
  if (isCurrentTransaction) log.warn("afterTransactionCompletion() was never called");
  
  if (connection!=null) { //ie it was never disconnected
    if ( connection.isClosed() ) {
      log.warn("finalizing unclosed session with closed connection");
    }
    else {
      log.warn("unclosed connection");
      if (autoClose) connection.close();
    }
  }
}

这个方法主要做的事情是检查应用程序是否忘记了关闭会话,如果是这样,则记录一个WARN。这是一个非常好的想法!否则很难注意到未关闭的会话及其拥有的JDBC连接。不幸的是,它有一个可怕的副作用,即阻止会话立即被垃圾回收。现在,即使阅读了这篇文章,我也没想到这会成为一个大问题,因为我几乎从close()中解引用了会话的所有状态。然而,我的性能测试显示,仅从移除终结器,性能就发生了很大的差异。对于一个问题,我实际上/减半了Hibernate的额外开销!

我几乎无法相信这个结果,但我已经成功地复制了它两个小时。


返回顶部