Uploaded image for project: 'Remoting JMX'
  1. Remoting JMX
  2. REMJMX-160

Every JMXConnectorFactory#connect() creates a new ThreadGroup which is never reclaimed

XMLWordPrintable

    • Icon: Bug Bug
    • Resolution: Done
    • Icon: Major Major
    • 1.1.3.Final, 3.0.1.Final
    • None
    • None
    • Hide
      • JMXClient.java
      import java.util.HashMap;
      import java.util.Map;
      import javax.management.MBeanServerConnection;
      import javax.management.remote.JMXConnector;
      import javax.management.remote.JMXConnectorFactory;
      import javax.management.remote.JMXServiceURL;
      
      public class JmxClient {
      
          public static void main(String[] args) throws Exception {
              for (int i = 0; i < 1000000; i++) {
                  String host = "localhost";
                  int port = 9990;  // management-http port
                  String urlString = "service:jmx:remote+http://" + host + ":" + port;
      
                  JMXServiceURL serviceURL = new JMXServiceURL(urlString);
      
                  Map map = new HashMap();
                  // When JMX credential is required, enable the following two lines
                  // String[] credentials = new String[] { "user", "password" };
                  // map.put("jmx.remote.credentials", credentials);
                  JMXConnector jmxConnector = JMXConnectorFactory.connect(serviceURL, map);
                  MBeanServerConnection connection = jmxConnector.getMBeanServerConnection();
      
                  int count = connection.getMBeanCount();
                  System.out.println(count);
      
                  jmxConnector.close();
      
                  System.out.println("Done: " + i);
              }
          }   
      }
      
      • Compile the above JMXClient application and execute against WildFly/JBoss EAP 7:
      $ javac -cp .:$JBOSS_HOME/bin/client/jboss-client.jar JmxClient.java
      $ java -cp .:$JBOSS_HOME/bin/client/jboss-client.jar JmxClient
      
      • Check the number of ThreadGroup instances periodically:
      $ jmap -histo:live <JMXClient_JAVA_PID> | grep ThreadGroup
      
      Show
      JMXClient.java import java.util.HashMap; import java.util.Map; import javax.management.MBeanServerConnection; import javax.management.remote.JMXConnector; import javax.management.remote.JMXConnectorFactory; import javax.management.remote.JMXServiceURL; public class JmxClient { public static void main( String [] args) throws Exception { for ( int i = 0; i < 1000000; i++) { String host = "localhost" ; int port = 9990; // management-http port String urlString = "service:jmx:remote+http: //" + host + ":" + port; JMXServiceURL serviceURL = new JMXServiceURL(urlString); Map map = new HashMap(); // When JMX credential is required, enable the following two lines // String [] credentials = new String [] { "user" , "password" }; // map.put( "jmx.remote.credentials" , credentials); JMXConnector jmxConnector = JMXConnectorFactory.connect(serviceURL, map); MBeanServerConnection connection = jmxConnector.getMBeanServerConnection(); int count = connection.getMBeanCount(); System .out.println(count); jmxConnector.close(); System .out.println( "Done: " + i); } } } Compile the above JMXClient application and execute against WildFly/JBoss EAP 7: $ javac -cp .:$JBOSS_HOME/bin/client/jboss-client.jar JmxClient.java $ java -cp .:$JBOSS_HOME/bin/client/jboss-client.jar JmxClient Check the number of ThreadGroup instances periodically: $ jmap -histo:live <JMXClient_JAVA_PID> | grep ThreadGroup
    • Hide
      • Reuse a JMXConnector object after it's created via JMXConnectorFactory#connect().
      • Pass a custom executor to JMXConnectorFactory.connect(url, map) by passing the environment map with the key "java.util.concurrent.Executor". See the attached JmxClientCustomExecutorWorkaround.java for details.
      Show
      Reuse a JMXConnector object after it's created via JMXConnectorFactory#connect(). Pass a custom executor to JMXConnectorFactory.connect(url, map) by passing the environment map with the key "java.util.concurrent.Executor". See the attached JmxClientCustomExecutorWorkaround.java for details.

      In JMX client application, every JMXConnectorFactory#connect() invocation creates a new ThreadGroup which is never reclaimed.

      https://github.com/jbossas/remoting-jmx/blob/3.0.1.Final/src/main/java/org/jboss/remotingjmx/protocol/v2/ClientExecutorManager.java#L51

      If a JMX client application lives for long periods of time and repeats to invoke JMXConnectorFactory#connect() and JMXConnector#close(), a lot of ThreadGroup instances are retained eventually.

        1. leaks.png
          leaks.png
          57 kB
        2. Memory.png
          Memory.png
          53 kB
        3. JmxClient.java
          1 kB
        4. JmxClientCustomExecutorWorkaround.java
          2 kB

            jboss-set_jira JBoss SET
            rhn-support-mmiura Masafumi Miura
            Votes:
            0 Vote for this issue
            Watchers:
            4 Start watching this issue

              Created:
              Updated:
              Resolved: