Java Memory Leak for JDBC

Java Memory Leak for JDBC

Post originally published on dev.to.

The Context

I had written an engine using a custom ClassLoader. To do that just create a new URLClassLoader, load a jar and execute what code you want, than close the URLClassLoader. If the new ClassLoader doesn’t have access to the current ClassLoader, the loaded classes does not have access to your code. Good! Very Good!

URL[] jars = new URL[] { /* The jars to be loaded */ }; //
try (URLClassLoader classLoader = new URLClassLoader(jars)) {
    Job job = classLoader.loadClass(Job.class.getName());
    job.execute();
}

The Problem

But… We do not have control with the code loaded from an external Jar. That is the problem. So if you want to avoid memory leaks the your custom classloader should be released by Garbage Collector. If the loaded code uses JDBC you will soon get an OutOfMemoryError and everything will crash! Not good!

The reason

Whe JDBC loads the driver they assumes that you will use only one ClassLoader, so it create a reference to your ClassLoader. This reference prevents the Garbage Collector from removing your custom ClassLoader from the memory.

So, even if you create your ClassLoader, execute your code and close it. The total of loaded classes will never decrease.

How to solve?

To solve this problem we have to unregister all JDBC drivers just after the execution, than close URLClassLoader.

URL[] jars = new URL[] { /* The jars to be loaded */ }; //
try (URLClassLoader classLoader = new URLClassLoader(jars)) {
  Job job = classLoader.loadClass(Job.class.getName());
  job.execute();
  Collections.list(DriverManager.getDrivers()).forEach(driver -> {
    try {
      DriverManager.deregisterDriver(driver);
    } catch (SQLException e) {
      logger.error("Error unregistering driver!", e);
    }
  });
} 

Now, let’s look for the loaded classes:

Possible problems

  1. If the executed code create any Thread, the URLClassLoader is not eligible for Garbage Collector.
  2. If some library create any Thread, same problem from #1.
  3. MongoDb client create a Thread. 😫
Originally published June 03, 2019