17

我在 tomcat 7 中有一个问题,这里有一些关于它的信息,

1 - 我有这个消息:

INFO: Reloading Context with name [/WebApp] has started
Oct 04, 2013 12:20:50 PM org.apache.catalina.loader.WebappClassLoader clearReferencesJdbc
SEVERE: The web application [/WebApp] registered the JDBC driver [com.mysql.jdbc.Driver] but failed to unregister it when the web application was stopped. To prevent a memory leak, the JDBC Driver has been forcibly unregistered.

Oct 04, 2013 12:20:50 PM org.apache.catalina.loader.WebappClassLoader clearReferencesThreads
SEVERE: The web application [/WebApp] appears to have started a thread named [Abandoned connection cleanup thread] but has failed to stop it. This is very likely to create a memory leak.
Oct 04, 2013 12:20:51 PM org.apache.catalina.core.StandardContext reload
INFO: Reloading Context with name [/WebApp] is completed

2 - 当我重新加载应用程序时,问题解决了大约 20 小时,然后又回来了。

3 - 我在 tomcat 上部署了大约 10 个应用程序,但其中只有 2 个出现此错误。

4 - 这两个应用程序的乞讨不存在问题,但从大约 2 周开始出现。

那么我该如何解决这个问题,它与我的代码有关吗?

4

2 回答 2

19

当您在 Tomcat 中停止 Web 应用程序时,它会尝试关闭它启动的线程并关闭一堆资源,例如 JDBC 驱动程序。虽然在这种情况下它能够关闭它们,但自己做会更安全。

您可以在ServletContextListener. 我已经实现了我的如下

@WebListener // register it as you wish
public class ContainerContextClosedHandler implements ServletContextListener {
    private static final Logger logger = LoggerFactory.getLogger(ContainerContextClosedHandler.class);

    @Override
    public void contextInitialized(ServletContextEvent servletContextEvent) {
        // nothing to do
    }

    @Override
    public void contextDestroyed(ServletContextEvent servletContextEvent) {
        Enumeration<Driver> drivers = DriverManager.getDrivers();     

        Driver driver = null;

        // clear drivers
        while(drivers.hasMoreElements()) {
            try {
                driver = drivers.nextElement();
                DriverManager.deregisterDriver(driver);

            } catch (SQLException ex) {
                // deregistration failed, might want to do something, log at the very least
            }
        }

        // MySQL driver leaves around a thread. This static method cleans it up.
        try {
            AbandonedConnectionCleanupThread.shutdown();
        } catch (InterruptedException e) {
            // again failure, not much you can do
        }
    }

}

MySQL 确实启动了一个 Tomcat 无法关闭的线程。对于当前版本(5.1.23+),他们提供了AbandonedConnectionCleanupThread关闭 spawned 的类Thread,如上所示。

于 2013-10-04T19:51:21.530 回答
7

If you have your Connector/J JDBC driver in each webapp's WEB-INF/lib directory, then you will likely have similar problems with all of your webapps -- not just this one.

If you are using Tomcat's JDBC connection pool, then you should put the Connector/J driver into Tomcat's lib/ directory and remove it from all of your webapps. If you are maintaining your own connection pool from within your own application, then you will have to arrange for the JDBC driver to be de-register itself with the global DriverManager. Better yet, use Connector/J's non-registering driver instead of the registering driver and then you don't have to worry about these kinds of leaks that Tomcat is actually protecting you from.

于 2013-10-04T20:18:49.393 回答