Tomcat Warning “To Prevent a Memory Leak, the JDBC Driver Has Been Forcibly Unregistered” – Tomcat警告“为防止内存泄漏,JDBC驱动程序已被强行取消注册&#8221。

最后修改: 2022年 6月 3日

1. Overview

1.概述

In this tutorial, we’ll look at the Tomcat warning message that informs us that it forcibly unregistered a JDBC driver. We’ll explore the meaning of the message, its root cause, and what we can do to mitigate it.

在本教程中,我们将研究Tomcat的警告信息,它告诉我们它强行取消了JDBC驱动的注册。我们将探讨该消息的含义、其根本原因,以及我们可以做些什么来减轻它的影响。

2. Message and Meaning

2.信息和意义

A version of the message could be the following:

该信息的一个版本可以是以下内容。

SEVERE: A web application registered the JBDC driver [oracle.jdbc.driver.OracleDriver]
  but failed to unregister it when the web application was stopped.
  To prevent a memory leak, the JDBC Driver has been forcibly unregistered.

With the above, Tomcat informs us that the JDBC driver class OracleDriver was registered when we deployed the web application, but it wasn’t unregistered when the same application was undeployed.

通过上述,Tomcat通知我们,JDBC驱动类OracleDriver在我们部署Web应用时被注册了,但在同一应用未部署时,它并没有被取消注册。

There are multiple ways we can load and register a JDBC driver, which is essentially a class that extends the java.sql.Driver interface. Tomcat uses the Java Service Provider Interface (SPI) and automatically loads any JDBC 4.0 compatible driver class that it can find under the web application’s WEB-INF/lib directory.

我们可以通过多种方式加载和注册 JDBC 驱动程序,其本质上是一个扩展 java.sql.Driver 接口的类。Tomcat 使用 Java 服务提供者接口 (SPI),并且 自动加载它在 Web 应用程序的 WEB-INF/lib 目录下能够找到的任何 JDBC 4.0 兼容驱动程序类

When we undeploy a web application, we must also unregister any drivers it brings. Otherwise, they remain registered with Tomcat. This creates a memory leak until we shut down the whole web server.

当我们取消部署一个Web应用程序时,我们也必须取消注册它带来的任何驱动程序。否则,它们将继续在Tomcat上注册。这将产生内存泄漏,直到我们关闭整个Web服务器

Since version 6.0.24, Tomcat detects this type of leak and forcibly unregisters all leaking drivers. However, it still informs us of the issue, which is very helpful if we deploy the same application on another web server that does not support this functionality.

从6.0.24版本开始,Tomcat检测到这种类型的泄漏,并强制解除所有泄漏的驱动程序的注册。然而,它仍然会通知我们这个问题,如果我们在不支持这个功能的另一个Web服务器上部署相同的应用程序,这将非常有帮助。

3. Root Cause and Potential Issues

3.根源和潜在的问题

The cause of the issue lies in the improper implementation of the JDBC driver. It should listen to the application undeployment event and unregister itself.

这个问题的原因在于JDBC驱动程序的不正确实现。它应该监听应用程序的取消部署事件,并取消自己的注册。

When the Java SPI loads a JDBC driver, it loads it using the current context class loader. Since the driver is under the application’s WEB-INF/lib, SPI loads it using its classloader. Drivers loaded in this way are registered with the DriverManager class, which is a JVM singleton. If this doesn’t happen, it introduces a memory leak in the loaded classes.

当Java SPI加载JDBC驱动程序时,它使用当前上下文class loader来加载它。由于驱动程序在应用程序的WEB-INF/lib下,SPI使用其类加载器加载它。以这种方式加载的驱动程序会在DriverManager类中注册,该类是一个JVM单例。如果不这样做,就会在加载的类中引入内存泄漏。

When we undeploy the web application, its class loader is garbage collected. On the other hand, the DriverManager still references the JDBC driver preventing garbage collection. If we deploy the same web application again, a new class loader is created, and SPI loads the same JDBC driver a second time. This is effectively a memory leak.

当我们取消部署Web应用程序时,它的类加载器被垃圾回收。另一方面,DriverManager仍然引用防止垃圾收集的JDBC驱动。如果我们再次部署相同的Web应用程序,就会创建一个新的类加载器,SPI就会第二次加载相同的JDBC驱动程序。这实际上是一个内存泄漏。

4. Mitigation Measures

4.缓解措施

There are multiple ways we can mitigate this problem.

我们有多种方法可以缓解这个问题。

4.1. Using Newer Tomcat Version

4.1.使用较新的Tomcat版本

Since version 6.0.24, Tomcat handles this issue automatically for us. This means that we can safely ignore the warning message.

从6.0.24版本开始,Tomcat自动为我们处理这个问题。这意味着我们可以安全地忽略该警告信息

4.2. Manual Deregistration on Shutdown

4.2.关机时手动取消注册

We can manually unregister the driver on any application shutdown callback. In the standard case where our application will have one JDBC driver loaded, we can do this with a single line of code:

我们可以在任何应用程序关机回调上手动取消驱动程序的注册。在标准情况下,我们的应用程序将加载一个JDBC驱动程序,我们可以通过一行代码来完成这个任务。

DriverManager.deregisterDriver(DriverManager.getDrivers().nextElement());

It is important to note that although Tomcat calls the action unregistration, the DriverManager method is called deregistration.

需要注意的是,虽然Tomcat称动作为取消注册,但DriverManager方法被称为取消注册。

4.3. Moving the JDBC Jar

4.3.移动 JDBC Jar

The official way to handle this is to move the JDBC driver jar file from the application’s WEB-INF/lib to Tomcat’s /lib directory. Since all jars under the /lib directory are also on the classpath, Tomcat will still automatically load the driver but under its own classloader.

官方的处理方法是将JDBC驱动的jar文件从应用程序的WEB-INF/lib移至Tomcat的/lib目录。由于/lib目录下的所有jar文件也在classpath上,Tomcat仍将自动加载驱动程序,但在它自己的classloader下。

Tomcat will not load any driver implementations when we deploy an application since there won’t be any under WEB-INF/lib. This means we can safely undeploy and redeploy it without loading anything new, thus preventing any leaks.

当我们部署一个应用程序时,Tomcat不会加载任何驱动实现,因为WEB-INF/lib下没有任何驱动。这意味着我们可以安全地取消部署和重新部署,而不加载任何新的东西,从而防止任何泄漏。

5. Conclusion

5.总结

In this article, we went over the meaning of the JDBC driver forcible unregistration warning message from Tomcat. We also looked at the root cause of it as well as possible ways to fix it.

在这篇文章中,我们讨论了来自Tomcat的JDBC驱动强行取消注册警告信息的含义。我们还研究了它的根本原因以及修复它的可能方法。