DEV Community πŸ‘©β€πŸ’»πŸ‘¨β€πŸ’»

DEV Community πŸ‘©β€πŸ’»πŸ‘¨β€πŸ’» is a community of 966,904 amazing developers

We're a place where coders share, stay up-to-date and grow their careers.

Create account Log in
Victor OsΓ³rio
Victor OsΓ³rio

Posted on

Java Memory Leak for JDBC

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. 😫

Top comments (0)

Earn our Top 7 Badge!

Write a post that gets featured in our weekly "must-reads" and you can earn this badge for your profile. 😎