Details

    • Type: Bug Bug
    • Status: Closed
    • Priority: Minor Minor
    • Resolution: Fixed
    • Affects Version/s: jdbc-1.1.3
    • Fix Version/s: jdbc-1.1.4
    • Labels:
      None
    • Environment:
      JDK 1.7.x, Tomcat 7.0.42
    • Global Rank:
      3510

      Description

      Hi,

      the MySQLStatement does start a TimerThread to handle the timeouts (which are e.g. applied in transactions).

      Stopping the webapplication does leak those thread because it is never stopped and the complete classloader fails to get garbage collected.
      My current workaround is, to call this in the contextDestroyed method of a webapp listener:

          try {
            final Class<?> clazz = ReflectionUtils.getClassForName("org.mariadb.jdbc.MySQLStatement");
            final Field f = clazz.getDeclaredField("timer");
            f.setAccessible(true);
            Timer timer = (Timer) f.get(null);
            if (timer != null) {
              timer.cancel();
            }
            timer = null;
          } catch (ClassNotFoundException | IllegalAccessException | NoSuchFieldException | SecurityException e) {
            // ignore
          }
      

      I've done similar for mysql, to stop the scheduler started to destroy connections.
      The difference is that there is an api call, a static method shutdown, to do this and i need no hacks to get that timer variable.

          try {
            final Class<?> clazz = ReflectionUtils.getClassForName("com.mysql.jdbc.AbandonedConnectionCleanupThread");
            MethodUtils.invokeExactStaticMethod(clazz, "shutdown", null);
          } catch (ClassNotFoundException e) {
            // ignore
          } catch (NoSuchMethodException e) {
            // ignore
          } catch (IllegalAccessException e) {
            // ignore
          } catch (InvocationTargetException e) {
            // ignore
          }
      

      Maybe you can implement similar.

      And if you do so, it would be nice if you can call the constructor, which does take a name for the Timer, e.g. MariaDBTimeoutStatementTimer, or something like this, to get rid of the "Timer-0" name in the thread overview to know what "Timer-0" is about for.

        Activity

        Hide
        Vladislav Vaintroub added a comment -

        Why do you think it is a leak? what happens if you start/stop webapp multiple times? How many Timer threads you'll have?

        Show
        Vladislav Vaintroub added a comment - Why do you think it is a leak? what happens if you start/stop webapp multiple times? How many Timer threads you'll have?
        Hide
        Torsten Krah added a comment - - edited

        The webapp has its own classloader which is pinned in memory because of those thread. The complete classloader fails to be collected because of that, so this is imho called a leak.

        Tomcat does even tell this:

        SEVERE: The web application [/] appears to have started a thread named [Timer-0] but has failed to stop it. This is very likely to create a memory leak.

        If i start the app twice, i get two timer threads, if i do this a third time, i get 3 timer threads and so on - until permgen space runs out of space.

        Show
        Torsten Krah added a comment - - edited The webapp has its own classloader which is pinned in memory because of those thread. The complete classloader fails to be collected because of that, so this is imho called a leak. Tomcat does even tell this: SEVERE: The web application [/] appears to have started a thread named [Timer-0] but has failed to stop it. This is very likely to create a memory leak. If i start the app twice, i get two timer threads, if i do this a third time, i get 3 timer threads and so on - until permgen space runs out of space.
        Hide
        Vladislav Vaintroub added a comment -

        I created a parameterless "unloadDriver" method in the org.mariadb.jdbc.Driver class for this.

        Show
        Vladislav Vaintroub added a comment - I created a parameterless "unloadDriver" method in the org.mariadb.jdbc.Driver class for this.
        Hide
        Torsten Krah added a comment -

        Can you please give the timer Thread a better name than "Timer"?

        Show
        Torsten Krah added a comment - Can you please give the timer Thread a better name than "Timer"?
        Hide
        Vladislav Vaintroub added a comment -

        It is the name given by the JVM.

        Show
        Vladislav Vaintroub added a comment - It is the name given by the JVM.
        Hide
        Vladislav Vaintroub added a comment -

        I mean, the timer class has the predefined name for this thread and I see no strong reason to give it a special name, even if it would make finding Tomcat classloader bugs easier.

        Show
        Vladislav Vaintroub added a comment - I mean, the timer class has the predefined name for this thread and I see no strong reason to give it a special name, even if it would make finding Tomcat classloader bugs easier.
        Hide
        Torsten Krah added a comment -

        To be honest - this has absolutely nothing to do with "obscure tomcat classloading bugs".
        This is just standard java classloading and garbage collection theory.

        Tomcat has its boot classloader and every webapp got its own webapp classloader. Any class loaded has a strong reference to its classloader.
        So is there is a Timer Thread running (which is a class loaded through the root classloader) and this does have a refercence to the MySQLStatement class (just the work the timer has to do). Because of this it also has a strong reference to the webapp classloader because this one did load the MySQLStatement class.
        So as long as this thread is running, the garbage collector can't collect the webapp classloader because there is still a strong reference to this one - through the Timer thread.

        Imho nothing obscure here - where do you see a tomcat classloading bug?

        And yes its the name the JDK does assign - but the JDK does also provide a constructor with a "name" arg to just name your timer thread to something meaningful.

        Just have a look at the http://www.java2s.com/Open-Source/Java-Open-Source-Library/Database/mysql/com/mysql/jdbc/AbandonedConnectionCleanupThread.java.htm code - they are calling the super constructor with a "name" to give their thread a nice name, not only "Thread-0" or something.
        In a webapp container this is really helpful to monitor stuff. Sometimes you got 10 or more "Timer-X" threads and wonder where are they coming from - it would help if they are named better, imho.

        Show
        Torsten Krah added a comment - To be honest - this has absolutely nothing to do with "obscure tomcat classloading bugs". This is just standard java classloading and garbage collection theory. Tomcat has its boot classloader and every webapp got its own webapp classloader. Any class loaded has a strong reference to its classloader. So is there is a Timer Thread running (which is a class loaded through the root classloader) and this does have a refercence to the MySQLStatement class (just the work the timer has to do). Because of this it also has a strong reference to the webapp classloader because this one did load the MySQLStatement class. So as long as this thread is running, the garbage collector can't collect the webapp classloader because there is still a strong reference to this one - through the Timer thread. Imho nothing obscure here - where do you see a tomcat classloading bug? And yes its the name the JDK does assign - but the JDK does also provide a constructor with a "name" arg to just name your timer thread to something meaningful. Just have a look at the http://www.java2s.com/Open-Source/Java-Open-Source-Library/Database/mysql/com/mysql/jdbc/AbandonedConnectionCleanupThread.java.htm code - they are calling the super constructor with a "name" to give their thread a nice name, not only "Thread-0" or something. In a webapp container this is really helpful to monitor stuff. Sometimes you got 10 or more "Timer-X" threads and wonder where are they coming from - it would help if they are named better, imho.

          People

          • Assignee:
            Vladislav Vaintroub
            Reporter:
            Torsten Krah
          • Votes:
            0 Vote for this issue
            Watchers:
            2 Start watching this issue

            Dates

            • Created:
              Updated:
              Resolved:

              Time Tracking

              Estimated:
              Original Estimate - Not Specified
              Not Specified
              Remaining:
              Remaining Estimate - 0 minutes
              0m
              Logged:
              Time Spent - 1 hour
              1h