问题描述:
警告 [localhost-startStop-2] org.apache.catalina.loader.WebappClassLoaderBase.clearReferencesJdbc The web application [XXXX] 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.
翻译过来的意思就是,JDBC没有注销,导致内存泄露,所以被系统强制注销了。
漫漫Debug长路:
1、网上说:“在服务器保持运行的状态中,redeploy这个项目, 就出现了异常,要stop之后 再redeploy,就可以了”
所以我就在任务管理器里面把tomcat kill掉了,然后再运行。
>>结果就是,依然报错。
2、网上说:“是tomcat的版本问题,tomcat新检测机制导致的这个问题,换版本可以解决问题,换到6以下的版本”
所以我就换了版本,但是很可惜,tomcat现在能下载的最低的版本就是6.0.48。
>>结果就是,依然报错。
3、网上说:“把Tomcat的内存增加一下”
所以我去把tomcat的内存从256M调至1024M(我的最大)
>>结果就是,依然报错。
4、网上说:“在tomcat的server.xml文件中,把<!-- Prevent memory leaks due to use of particular java/javax APIs-->
<Listener className="org.apache.catalina.core.JreMemoryLeakPreventionListener"/>;这个监听给关了。”
我知道这个方法治标不治本,但是我真的去关了。
>>结果就是,关了一个JreMemoryLeakPreventionListener没用,报错。索性把它附近的全部listener都关闭了。 呵呵,还是报错。
【这个时候有点儿崩溃了,挺住,继续,坚持!!】
5、网上说:“可能是jar包的问题,把JDBC的jar包放到lib下面,把app的jar包删除”
>>我做了,没用。
【很崩溃,怎么做都不对,服务器低配又卡的一死一死的,而且已经深夜11点了,心情非常沮丧】
然后我就打开程序媛群,把错误信息发给她们,问问她们有没有遇到过。
女神给我的回复是:“内存泄露,得治本。”
所以我就开始了漫漫走读代码的过程。
我发现我的数据库用了好像确实没关? 所以我在函数里写了connetion.close()
>>当然这就是导致我后面程序能运行但是出错的根源,不能乱关!没用完别急着关!
然后我发现我的注册函数 load ,里面用了一个 destory()方法,但是我没有覆写它。
所以我就:
public void destroy() {
super.destroy();
try{
DriverManager.deregisterDriver(DriverManager.getDrivers().nextElement());
}catch(Exception e){
e.printStackTrace();
}
}
这个是从:http://hongjiang.info/tomcat-jdbc-leak-prevention/这个帖子里得到的启发。
“对JDBC Driver的清理,是clearReferencesJdbc
方法,它检查当前WebappClassLoader加载过的,在关闭时未注销掉的JDBC Driver,给出警告信息,并强行将这些Driver反注册掉。”
“销毁时未将这个Driver给反注册掉;这时不管是显式的通过命令来stop tomcat,还是因为设置了自动reload,而且恰好检查到应用有变,执行了reload的时候(reload也是对app context进行stop,然后再重新start),就会被tomcat判断为泄露,给出警告并强制反注册Driver”
“要避免这个信息,应用或框架应该自己来保证在销毁时将JDBC Driver反注册掉。”
最后,感谢,成功了