The web application [] registered the JDBC driver [com.mysql.jdbc.Driver] but failed to unregister it when the web application was stopped
Your application doesn't have a flaw. It is the design of JDBC. The JDBC driver gets loaded and registered by the webapp when it creates a database connection for the first time.
That means that the driver is loaded with the web application class loader. On undeployment the driver doesn't get deregistered which in turn prevents your webapp classes from GC. That creates effectively a memory leak.
To prevent this particular memory leak you should edit your tomcat/conf/server.xml
and change
<Listener className="org.apache.catalina.core.JreMemoryLeakPreventionListener" />
to
<Listener
className="org.apache.catalina.core.JreMemoryLeakPreventionListener"
classesToInitialize="com.mysql.jdbc.NonRegisteringDriver" />
- With mysql-connector-java-8.0.x use
com.mysql.cj.jdbc.NonRegisteringDriver
instead
Exclude the JDBC driver from your webapp artifact and put it into the tomcat/lib
directory.
Now the JDBC driver gets loaded by Tomcat on startup and isn't linked to any webapps class loader.
Why should I modify the server.xml?
Another memory leaks manifests due to MySQL's 'Abandoned connection cleanup thread'. This thread starts with the first request and holds a reference to the webapp's classloader. With classesToInitialize
you can prevent this memory leak too.
References:
- org.apache.catalina.core.JreMemoryLeakPreventionListener tomcat-doc v7.0
- AbandonedConnectionCleanupThread notes in v5.1.41
- com.mysql.jdbc.NonRegisteringDriver source v5.1
- com.mysql.cj.jdbc.NonRegisteringDriver source v8.0
- mysql-connector-java changes in v8.0
What I did was just to put the mysql-connector-java-5.1.31-bin.jar
in $CATALINA_HOME/lib
. No modifications to server.xml
.