Commons Dbcp
  1. Commons Dbcp
  2. DBCP-332

Closing BasicDataSource doesn't deregister JDBC driver, causing memory leak

    Details

    • Type: Bug Bug
    • Status: Closed
    • Priority: Major Major
    • Resolution: Won't Fix
    • Affects Version/s: 1.3, 1.4
    • Fix Version/s: None
    • Labels:
      None

      Description

      BasicDataSource's method close() doesn't deregister JDBC driver. This causes permgen memory leaks in web server environments, during context reloads. For example, using Tomcat 6.0.26 with Spring, and BasicDataSource declared in Spring context, there is a message printed at web application reload:

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

      I was able to fix it by overriding close method this way:

      public class XBasicDataSource extends BasicDataSource {
          @Override
          public synchronized void close() throws SQLException {
              DriverManager.deregisterDriver(DriverManager.getDriver(url));
              super.close();
          }
      }
      

      but I think it should be probably the default behavior of BasicDataSource. Or perhaps there should be some flag/setting on BasicDataSource, named "deregisterDriverAtClose" or so.

        Activity

        Hide
        Phil Steitz added a comment -

        Could this be a regression introduced by the fix for DBCP-272?

        Show
        Phil Steitz added a comment - Could this be a regression introduced by the fix for DBCP-272 ?
        Hide
        Grzegorz Borkowski added a comment -

        I don't think so. DBCP-272 talks about initialization process - when and how driver should be registered, from what I see. But the net result is the same: driver gets registered.
        Here I mean the fact, the it is not unregistered during closing the SimpleDataSource - which causes memory leak, and Tomcat complains about it.

        Show
        Grzegorz Borkowski added a comment - I don't think so. DBCP-272 talks about initialization process - when and how driver should be registered, from what I see. But the net result is the same: driver gets registered. Here I mean the fact, the it is not unregistered during closing the SimpleDataSource - which causes memory leak, and Tomcat complains about it.
        Hide
        Sebb added a comment -

        Is it possible for multiple data sources to register the same driver?

        If so, won't deregistering it in one cause problems for the others?

        Show
        Sebb added a comment - Is it possible for multiple data sources to register the same driver? If so, won't deregistering it in one cause problems for the others?
        Hide
        Grzegorz Borkowski added a comment -

        If they all use the same classloader, than probably yes, this could cause the problem - it needs verification, but it sounds logical. If that's the case, than it would be better to make this behavior optional. So add the method "deregisterDriver" to BasicDataSource so that I can call it from some listener programatically. Also, add settings "deregisterDriverOnClose", so that I can set up BasicDataSource, for example in Spring, with this option set to true, so that it dergisters the driver automatically, and I don't have to write any code, only by pure configuration.

        Show
        Grzegorz Borkowski added a comment - If they all use the same classloader, than probably yes, this could cause the problem - it needs verification, but it sounds logical. If that's the case, than it would be better to make this behavior optional. So add the method "deregisterDriver" to BasicDataSource so that I can call it from some listener programatically. Also, add settings "deregisterDriverOnClose", so that I can set up BasicDataSource, for example in Spring, with this option set to true, so that it dergisters the driver automatically, and I don't have to write any code, only by pure configuration.
        Hide
        Daniele added a comment -

        In which Tomcat version it has been corrected ? 6.0.25 ?

        Show
        Daniele added a comment - In which Tomcat version it has been corrected ? 6.0.25 ?
        Hide
        Grzegorz Borkowski added a comment -

        6.0.24

        Show
        Grzegorz Borkowski added a comment - 6.0.24
        Hide
        Daniele added a comment -

        I have Tomcat 6.0.24 and in my catalina.log i see this error:

        A web application registered the JBDC driver [com.microsoft.sqlserver.jdbc.SQLServerDriver] but failed to unregister it when the web application was stopped. To prevent a memory leak, the JDBC Driver has been forcibly unregistered.
        A web application appears to have started a thread named [Thread-4] but has failed to stop it. This is very likely to create a memory leak.

        Show
        Daniele added a comment - I have Tomcat 6.0.24 and in my catalina.log i see this error: A web application registered the JBDC driver [com.microsoft.sqlserver.jdbc.SQLServerDriver] but failed to unregister it when the web application was stopped. To prevent a memory leak, the JDBC Driver has been forcibly unregistered. A web application appears to have started a thread named [Thread-4] but has failed to stop it. This is very likely to create a memory leak.
        Hide
        Grzegorz Borkowski added a comment -

        @Daniele: what you see in Tomcat logs means that Tomcat sees that there is memory leak, and it tries to prevent it. In earlier Tomcat versions, you wouldn't see it.

        Show
        Grzegorz Borkowski added a comment - @Daniele: what you see in Tomcat logs means that Tomcat sees that there is memory leak, and it tries to prevent it. In earlier Tomcat versions, you wouldn't see it.
        Hide
        Grzegorz Borkowski added a comment -

        I've discovered one problem with unregistering SQL driver in BasicDataSource.close() method: if you create the BasicDataSource, retrieve connection, close connection, than close BDS, and than create new instance of BDS, and try to obtain connection, it will not work: it will complain that it can't find proper driver for given URL. I haven't had time to investigate it, but I guess that driver registration is done somehow statically, at class loading. So after you deregister driver and create new instance of BDS, driver is not registered again, because no classlodin is done at that moment. That's my guess at least. As a solution, the BDS could try to register manually the driver (using java.sql.DriverManager.registerDriver) whenever first attempt to obtain driver fails.

        Show
        Grzegorz Borkowski added a comment - I've discovered one problem with unregistering SQL driver in BasicDataSource.close() method: if you create the BasicDataSource, retrieve connection, close connection, than close BDS, and than create new instance of BDS, and try to obtain connection, it will not work: it will complain that it can't find proper driver for given URL. I haven't had time to investigate it, but I guess that driver registration is done somehow statically, at class loading. So after you deregister driver and create new instance of BDS, driver is not registered again, because no classlodin is done at that moment. That's my guess at least. As a solution, the BDS could try to register manually the driver (using java.sql.DriverManager.registerDriver) whenever first attempt to obtain driver fails.
        Hide
        Mark Thomas added a comment -

        I've been thinking about this and there are enough use cases where you don't want this to happen - a number of them articulated in this bug report - that I think that it makes more sense to leave de-registration of the JDBC driver as a client responsibility. It is much easier for the client to de-register the driver when it knows it is safe to do so than it is to add a bunch of configuration options and other complexity to DBCP.

        Show
        Mark Thomas added a comment - I've been thinking about this and there are enough use cases where you don't want this to happen - a number of them articulated in this bug report - that I think that it makes more sense to leave de-registration of the JDBC driver as a client responsibility. It is much easier for the client to de-register the driver when it knows it is safe to do so than it is to add a bunch of configuration options and other complexity to DBCP.
        Hide
        Stevo Slavic added a comment -

        It would be nice to document this.

        Show
        Stevo Slavic added a comment - It would be nice to document this.

          People

          • Assignee:
            Unassigned
            Reporter:
            Grzegorz Borkowski
          • Votes:
            20 Vote for this issue
            Watchers:
            13 Start watching this issue

            Dates

            • Created:
              Updated:
              Resolved:

              Development