Tomcat中Web应用程序停止时为了防止内存泄漏,JDBC驱动程序被强制取消注册出现原因
1.问题描述
本地Windows环境开发的Springboot项目同样的mysql版本,jdk版本,tomcat版本,本地运行没有任何问题,发布到阿里云服务器上时报以下问题:
06-May-2025 20:06:12.842 警告 [main] org.apache.catalina.loader.WebappClassLoaderBase.clearReferencesJdbc Web应用程序 [xxxxx-admin] 注册了JDBC驱动程序 [com.alibaba.druid.proxy.DruidDriver],但在Web应用程序停止时无法注销它。 为防止内存泄漏,JDBC驱动程序已被强制取消注册。
06-May-2025 20:06:12.842 警告 [main] org.apache.catalina.loader.WebappClassLoaderBase.clearReferencesJdbc Web应用程序 [xxxxx-admin] 注册了JDBC驱动程序 [com.mysql.jdbc.Driver],但在Web应用程序停止时无法注销它。 为防止内存泄漏,JDBC驱动程序已被强制取消注册。
06-May-2025 20:06:12.852 警告 [main] org.apache.catalina.loader.WebappClassLoaderBase.clearReferencesThreads Web应用程序[xxxxx-admin]似乎启动了一个名为[crmeb-scheduled-task-pool-1]的线程,但未能停止它。这很可能会造成内存泄漏。线程的堆栈跟踪:[
sun.misc.Unsafe.park(Native Method)
java.util.concurrent.locks.LockSupport.park(LockSupport.java:175)
java.util.concurrent.locks.AbstractQueuedSynchronizer$ConditionObject.await(AbstractQueuedSynchronizer.java:2039)
java.util.concurrent.ScheduledThreadPoolExecutor$DelayedWorkQueue.take(ScheduledThreadPoolExecutor.java:1088)
java.util.concurrent.ScheduledThreadPoolExecutor$DelayedWorkQueue.take(ScheduledThreadPoolExecutor.java:809)
java.util.concurrent.ThreadPoolExecutor.getTask(ThreadPoolExecutor.java:1074)
java.util.concurrent.ThreadPoolExecutor.runWorker(ThreadPoolExecutor.java:1134)
java.util.concurrent.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:624)
java.lang.Thread.run(Thread.java:748)]
和
以上异常信息,上网查找了很多,终于成功解决。
解决办法:
手动配置监听器,用来在Tomcat关闭时取消注册JDBC驱动程序,并将线程停止
编写自定义监听器
代码如下:
import javax.servlet.ServletContextEvent;
import javax.servlet.ServletContextListener;
import javax.servlet.annotation.WebListener;
//mysql8及以上用 com.mysql.cj
import com.mysql.jdbc.AbandonedConnectionCleanupThread;
//import com.mysql.cj.jdbc.AbandonedConnectionCleanupThread;
import java.sql.Driver;
import java.sql.DriverManager;
import java.sql.SQLException;
import java.util.Enumeration;
@WebListener
public class DriverMangerListener implements ServletContextListener {
public void contextInitialized(ServletContextEvent sce) {
}
public void contextDestroyed(ServletContextEvent sce) {
AbandonedConnectionCleanupThread.uncheckedShutdown();
Enumeration<Driver> enumeration = DriverManager.getDrivers();
while (enumeration.hasMoreElements()) {
try {
DriverManager.deregisterDriver(enumeration.nextElement());
} catch (SQLException e) {
e.printStackTrace();
}
}
}
}
我的是Springboot项目直接用@WebListener注解即可,要是ssm或者springmvc项目的话,在web.xml中添加以下代码注册该listener即可,注意类的路径以及该配置所在文件中的位置。
<listener><listener-class>com.ssm.util.DriverMangerListener</listener-class> </listener>