首页
学习
活动
专区
工具
TVP
发布
社区首页 >问答首页 >为防止内存泄漏,已强制取消注册JDBC驱动程序

为防止内存泄漏,已强制取消注册JDBC驱动程序
EN

Stack Overflow用户
提问于 2010-07-24 00:45:16
回答 14查看 396.9K关注 0票数 338

当我运行我的web应用程序时,我得到了这个消息。它运行得很好,但我在关机时收到以下消息。

严重: web应用程序注册了JBDC驱动程序oracle.jdbc.driver.OracleDriver,但在web应用程序停止时未能将其注销。为了防止内存泄漏,JDBC驱动程序已被强制注销。

感谢您的帮助。

EN

回答 14

Stack Overflow用户

回答已采纳

发布于 2010-07-24 01:01:53

从版本6.0.24开始,Tomcat附带了memory leak detection功能,当webapp的/WEB-INF/lib中有一个与JDBC 4.0兼容的驱动程序时,会导致这种警告消息,该驱动程序在webapp的启动过程中使用ServiceLoader API自动registers自己,但在webapp的关闭过程中没有自动deregister自己。此消息纯粹是非正式的,Tomcat已经采取了相应的内存泄漏预防措施。

你能做什么?

  1. 会忽略这些警告。Tomcat的工作做得很好。实际的bug在别人的代码中(有问题的JDBC驱动程序),而不是在您的代码中。很高兴Tomcat正确地完成了它的工作,并等待JDBC驱动程序供应商将其修复,以便您可以升级驱动程序。另一方面,您不应该在webapp的/WEB-INF/lib中删除JDBC驱动程序,而只能在服务器的/lib中删除。如果您仍将其保留在webapp的/WEB-INF/lib中,则应使用ServletContextListener.

手动注册和取消注册

  1. 降级到Tomcat6.0.23或更早的版本,这样你就不会被这些警告困扰了。但它会默默地保持内存泄漏。我不确定这到底是不是好消息。这种内存泄漏是Tomcat hotdeployments.

期间OutOfMemoryError issues背后的主要原因之一

  1. 将JDBC驱动程序移到Tomcat的/lib文件夹中,并使用连接池数据源来管理该驱动程序。请注意,Tomcat的内置DBCP不能在关闭时正确注销驱动程序。另请参阅bug DBCP-322,它被关闭为WONTFIX。您更愿意用另一个比DBCP做得更好的连接池来替换DBCP。例如,HikariCPTomcat JDBC Pool.
票数 311
EN

Stack Overflow用户

发布于 2011-03-16 01:20:49

在servlet上下文侦听器contextDestroyed()方法中,手动注销驱动程序:

代码语言:javascript
复制
// This manually deregisters JDBC driver, which prevents Tomcat 7 from complaining about memory leaks wrto this class
Enumeration<Driver> drivers = DriverManager.getDrivers();
while (drivers.hasMoreElements()) {
    Driver driver = drivers.nextElement();
    try {
        DriverManager.deregisterDriver(driver);
        LOG.log(Level.INFO, String.format("deregistering jdbc driver: %s", driver));
    } catch (SQLException e) {
        LOG.log(Level.SEVERE, String.format("Error deregistering driver %s", driver), e);
    }
}
票数 169
EN

Stack Overflow用户

发布于 2014-05-28 20:56:56

尽管Tomcat确实会强制取消JDBC驱动程序的注册,但最好还是清理webapp在上下文销毁时创建的所有资源,以防您移动到另一个servlet容器,该容器不会执行Tomcat所做的内存泄漏预防检查。

然而,全面注销驱动程序的方法是危险的。DriverManager.getDrivers()方法返回的一些驱动程序可能已由父ClassLoader (即servlet容器的类加载器)加载,而不是webapp上下文的ClassLoader加载(例如,它们可能在容器的lib文件夹中,而不是webapp的ClassLoader文件夹中,因此在整个容器中共享)。取消这些注册将影响任何其他可能正在使用它们的the应用程序(甚至是容器本身)。

因此,在取消注册之前,应该检查每个驱动程序的ClassLoader是否为webapp应用程序的ClassLoader。因此,在ContextListener的contextDestroyed()方法中:

代码语言:javascript
复制
public final void contextDestroyed(ServletContextEvent sce) {
    // ... First close any background tasks which may be using the DB ...
    // ... Then close any DB connection pools ...

    // Now deregister JDBC drivers in this context's ClassLoader:
    // Get the webapp's ClassLoader
    ClassLoader cl = Thread.currentThread().getContextClassLoader();
    // Loop through all drivers
    Enumeration<Driver> drivers = DriverManager.getDrivers();
    while (drivers.hasMoreElements()) {
        Driver driver = drivers.nextElement();
        if (driver.getClass().getClassLoader() == cl) {
            // This driver was registered by the webapp's ClassLoader, so deregister it:
            try {
                log.info("Deregistering JDBC driver {}", driver);
                DriverManager.deregisterDriver(driver);
            } catch (SQLException ex) {
                log.error("Error deregistering JDBC driver {}", driver, ex);
            }
        } else {
            // driver was not registered by the webapp's ClassLoader and may be in use elsewhere
            log.trace("Not deregistering JDBC driver {} as it does not belong to this webapp's ClassLoader", driver);
        }
    }
}
票数 95
EN
页面原文内容由Stack Overflow提供。腾讯云小微IT领域专用引擎提供翻译支持
原文链接:

https://stackoverflow.com/questions/3320400

复制
相关文章

相似问题

领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档