最近有几个服务的Tomcat总是无缘无故的宕机,到了不得不解决的地步。
在Stackoverflow上找到比较有用的一篇文章,解决方案如下:
http://stackoverflow.com/questions/3320400/to-prevent-a-memory-leak-the-jdbc-driver-has-been-forcibly-unregistered
有以下几个解决途径:
-
Ignore those warnings. Tomcat is doing its job right. The actual bug is in someone else's code (the JDBC driver in question), not in yours. Be happy that Tomcat did its job properly and wait until the JDBC driver vendor get it fixed so that you can upgrade the driver. On the other hand, you aren't supposed to drop a JDBC driver in webapp's /WEB-INF/lib
, but only in server's /lib
. If you still keep it in webapp's /WEB-INF/lib
, then you should manually register and deregister it using a ServletContextListener
.
忽略警告。把WEB-INF/lib下的mysql驱动文件拷贝到Tomcat/lib下。如果仍然要放在WEB-INF/lib下,需要使用监听器手动的注册和注销。
下面的文章介绍如何写监听器,http://javabeat.net/servletcontextlistener-example/, 当然如果是Servlet3.0, 使用注解方式设置监听也是可以的。
下面的代码是如何注销。
Step 1: Register a Listener
web.xml
<listener>
<listener-class>com.mysite.MySpecialListener</listener-class>
</listener>
Step 2: Implement the Listener
com.mysite.MySpecialListener.java
public class MySpecialListener extends ApplicationContextListener {
@Override
public void contextInitialized(ServletContextEvent sce) {
// On Application Startup, please…
// Usually I'll make a singleton in here, set up my pool, etc.
}
@Override
public void contextDestroyed(ServletContextEvent sce) {
// 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);
}
}
}
}
-
Downgrade to Tomcat 6.0.23 or older so that you will not be bothered with those warnings. But it will silently keep leaking memory. Not sure if that's good to know after all. Those kind of memory leaks are one of the major causes behind OutOfMemoryError
issues during Tomcat hotdeployments.
把Tomcat降级到低版本(6.0.23以下),虽然不会报错,但是还是存在内存益出的问题,这并不是一个好的解决方案。
-
Move the JDBC driver to Tomcat's /lib
folder and have a connection pooled datasource to manage the driver. Note that Tomcat's builtin DBCP does not deregister drivers properly on close. See also bug DBCP-322 which is closed as WONTFIX. You would rather like to replace DBCP by another connection pool which is doing its job better then DBCP. For exampleHikariCP, BoneCP, or perhaps Tomcat JDBC Pool.
把驱动文件移到Tomcat/lib文件夹下,不用使用DBCP,使用以下的连接池库,HikariCP, BoneCP,或者Tomcat JDBC Pool.
- MAVEN项目
If you are getting this message from a Maven built war change the scope of the JDBC driver to provided, and put a copy of it in the lib directory. Like this:<dependency>,
对于MAVEN项目,由于Tomcat中存在mysql驱动文件(1中介绍),这样在部署时就不会把mysql带到打包文件里,注意是<scope>provided</scope>。
<groupId>mysql</groupId>
<artifactId>mysql-connector-java</artifactId>
<version>5.1.18</version>
<!-- put a copy in /usr/share/tomcat7/lib -->
<scope>provided</scope>
</dependency>
好了,如果您遇到同样的问题,可以和我沟通,联系方式见头部。