I have created a REST service in which I am loading the JDBC driver jar at runtime. Below is the code which does this:
Driver driverInstance;
URLClassLoader driverClassLoader;
driverClassLoader = new URLClassLoader (new URL[] { "c:/mysql.jar" }, System.class.getClassLoader());
Class<?> driverClass = driverClassLoader.loadClass("oracle.jdbc.driver.OracleDriver");
Connection conn = driverInstance.connect(connectionString, userDbCredentials);
After using this connection to load data into database, I am closing the connection and driverClassLoader both. But after running it for some time, I am getting java.lang.OutOfMemoryError: PermGen space in tomcat server.
I took the heap dump, and open it using eclipse Memory Analyzer and I found that the below Leak suspect message: 13 instances of "org.apache.catalina.loader.WebappClassLoader", loaded by "java.net.URLClassLoader @ 0xc155fc10" occupy 14,083,776 (32.21%) bytes
I understand that it is due to loading of driver jar at runtime but I am unable to find a solution to it.
When you load the JDBC driver class, it registers itself with
java.sql.DriverManager
. Even though you try to make the system classloader the parent of yourURLClassLoader
, I believe it will inherit theAccessControlContext
from yourWebappClassLoader
, thus referencing it. Analyzing the references using Eclipse Memory Analyzer (MAT) could help verify that - see this blog post for instructions.Assuming that the JDBC driver is in fact the source of the leak, the solution to your problems is to call
java.sql.DriverManager.deregisterDriver()
to explicitly deregister the driver, preferably in thecontextDestroyed()
of aServletContextListener
.Normally you could let my ClassLoader leak prevention library take care of the deregistering for you, however since the driver is loaded in a separate classloader it won't work out of the box. You may however be able to do some subclassing/modification. The benefit would be that you get a lot more leak protection for free.
Whether you really want and need to load drivers from outside the application at runtime - well, that's a separate question...
Good luck!