Eclipse调试模式重启Tomcat时Hibernate 5.0.7运行阻塞问题求助
问题根因
核心根因为以下两点关联问题:
- Tomcat停止应用时未正确销毁Hibernate资源,遗留
Timer-0调度线程,该线程持有旧Web应用类加载器的引用,触发类加载器泄漏,对应停止时的内存泄漏警告。 - 调试模式下Eclipse会额外持有类加载相关的锁,重启应用时Hibernate执行
metadataBuilder.build()构建元数据的过程需要加载映射类、获取类加载器锁,和遗留线程持有的锁冲突触发死锁,所以会在HibernateUtil.getSessionFactory().getCurrentSession().beginTransaction();处阻塞。运行模式没有调试器的额外锁逻辑,不会触发死锁,因此运行正常。重启电脑会销毁所有遗留线程,所以首次启动可以正常运行。
解决步骤
1. 修复Hibernate资源泄漏(永久解决核心问题)
在HibernateSessionRequestFilter的destroy()生命周期方法中,主动关闭Hibernate SessionFactory,添加代码如下:
@Override public void destroy() { if (HibernateUtil.getSessionFactory() != null && !HibernateUtil.getSessionFactory().isClosed()) { HibernateUtil.getSessionFactory().close(); } }
Web应用卸载时会自动执行该方法,主动关闭Hibernate内部的Timer线程、释放所有持有的资源,从根源避免线程泄漏。
2. 调整Eclipse调试配置(降低死锁概率)
打开Eclipse的「窗口」-「偏好设置」-「Java」-「调试」,取消勾选暂停执行在未捕获的异常上、启用类加载追踪两个选项,减少调试器额外的锁占用。
3. 配置Tomcat兜底避免泄漏
打开Tomcat安装目录下conf/context.xml,在<Context>节点中添加如下配置,强制Tomcat卸载应用时清理遗留子线程:
<Context> <!-- 新增如下两行配置 --> <Loader abandonWhenPercentageFull="100" reloadable="true" /> <Manager destroyOnShutdown="true" /> </Context>
4. 临时快速恢复方案
修改配置前如果遇到阻塞问题,不需要重启电脑,打开任务管理器结束所有javaw.exe(对应Eclipse启动的Tomcat进程)进程,再重启调试模式即可正常运行。
内容的提问来源于stack exchange,提问作者xc93hil
相关产品推荐
相关产品推荐

