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的额外开销!
我几乎无法相信这个结果,但我已经成功地复制了它两个小时。