JGroups
  1. JGroups
  2. JGRP-1410

globalThreadGroup not destroyed creates a classloader memory leak

    Details

    • Type: Bug Bug
    • Status: Resolved Resolved (View Workflow)
    • Priority: Major Major
    • Resolution: Done
    • Affects Version/s: 3.0.1
    • Fix Version/s: 3.2.2, 3.3
    • Labels:
      None
    • Environment:
      linux w/ java 1.6
    • Workaround:
      Workaround Exists
    • Workaround Description:
      Hide

      It is possible to manually destroy the thread group at web application shutdown (for example, in the destroy() method of a servlet):

      ThreadGroup globalThreadGroup = Util.getGlobalThreadGroup();
      
      if (!globalThreadGroup.isDestroyed()) {
      
          if (globalThreadGroup.activeCount() > 0) {
              mLog.warn("Active threads still running in JGroups global thread group.  Waiting 2 seconds.");
              try {
                  Thread.sleep(2000);
              } catch (InterruptedException exception) {
                  Thread.currentThread().interrupt();
              }
          
              if (globalThreadGroup.activeCount() > 0) {
                  mLog.warn("Active threads still running in JGroups global thread group.  Interrupting all threads.");
                  globalThreadGroup.interrupt();
              } else {
                  mLog.info("No active threads in JGroups global thread group.");
              }
          }
      
          try {
              globalThreadGroup.destroy();
          } catch (Exception exception) {
              mLog.error("Error while destroying JGroups global thread group.", exception);
          }
      }
      
      
      Show
      It is possible to manually destroy the thread group at web application shutdown (for example, in the destroy() method of a servlet): ThreadGroup globalThreadGroup = Util.getGlobalThreadGroup(); if (!globalThreadGroup.isDestroyed()) { if (globalThreadGroup.activeCount() > 0) { mLog.warn( "Active threads still running in JGroups global thread group. Waiting 2 seconds." ); try { Thread .sleep(2000); } catch (InterruptedException exception) { Thread .currentThread().interrupt(); } if (globalThreadGroup.activeCount() > 0) { mLog.warn( "Active threads still running in JGroups global thread group. Interrupting all threads." ); globalThreadGroup.interrupt(); } else { mLog.info( "No active threads in JGroups global thread group." ); } } try { globalThreadGroup.destroy(); } catch (Exception exception) { mLog.error( "Error while destroying JGroups global thread group." , exception); } }
    • Similar Issues:
      Show 10 results 

      Description

      When all channels are closed, the globalThreadGroup is not destroyed. For a normal (i.e. non-web) application, this is not a problem since the process will exit anyway. However, for a Java Enterprise web application, this causes a classloader memory leak since the ThreadGroup object has strong references to JGroups instances having strong references to their class object having strong reference to their class loader. Since the class loader is pointed by strong references, the it cannot be garbage collected and hence a leak is created each time the web application is stopped.

        Issue Links

          Activity

          Hide
          Bela Ban
          added a comment -

          Reading up on thread groups, I found out that they're not really recommended nowadays anymore, e.g. google for "ThreadGroup Doug Lea". So we could get rid of thread groups altogether, I'll investigate more...

          Show
          Bela Ban
          added a comment - Reading up on thread groups, I found out that they're not really recommended nowadays anymore, e.g. google for "ThreadGroup Doug Lea". So we could get rid of thread groups altogether, I'll investigate more...
          Hide
          Bela Ban
          added a comment -

          I removed the use of ThreadGroup, as suggested in my prev comment. I also fixed a bug that caused timer threads to have a null or <ADDR> cluster name when a shared transport was used.
          Let me know if this fixes your classloading leak, and re-open if the leak still exists.

          Show
          Bela Ban
          added a comment - I removed the use of ThreadGroup, as suggested in my prev comment. I also fixed a bug that caused timer threads to have a null or <ADDR> cluster name when a shared transport was used. Let me know if this fixes your classloading leak, and re-open if the leak still exists.
          Hide
          Bela Ban
          added a comment -

          Contrary to 3.3, ThreadGroups were not removed in the 3.2 branch (change would have been too big). Instead, luksa provided a PR which made the channel TG a static inner class

          Show
          Bela Ban
          added a comment - Contrary to 3.3, ThreadGroups were not removed in the 3.2 branch (change would have been too big). Instead, luksa provided a PR which made the channel TG a static inner class
          Hide
          Mattias Jiderhamn
          added a comment -

          There seems to be another one of these, see JGRP-1576

          Show
          Mattias Jiderhamn
          added a comment - There seems to be another one of these, see JGRP-1576
          Hide
          Mattias Jiderhamn
          added a comment -

          For those not able to upgrade due to dependencies, this library also provides a workaround for both this issue and JGRP-1576: https://github.com/mjiderhamn/classloader-leak-prevention

          Show
          Mattias Jiderhamn
          added a comment - For those not able to upgrade due to dependencies, this library also provides a workaround for both this issue and JGRP-1576 : https://github.com/mjiderhamn/classloader-leak-prevention

            People

            • Assignee:
              Bela Ban
              Reporter:
              Jean-Philippe Gariepy
            • Votes:
              1 Vote for this issue
              Watchers:
              5 Start watching this issue

              Dates

              • Created:
                Updated:
                Resolved: