This discussion is archived
4 Replies Latest reply: Jun 27, 2012 3:46 AM by 946114 RSS

Is this a known bug? OOME because of MBeanServerConnection addListener

843798 Newbie
Currently Being Moderated
Hi

I use a JMXConnector to monitor different processes. For each MBean (which is
also a NotificationBroadcaster)registered in the monitored process a listener
is added by the monitoring process.

Now the problem is that I'm not able to remove this listener when the MBean is
removed by the monitored process. After a long time this causes the monitored
process to crash by a "java.lang.OutOfMemoryError: PermGen space".

The analysis shows that the ObjectNames added by the listener are never gc'ed.
They are held by ServerNotifForwarder's listenerMap. The OOME is in the PermGen
because of the String.intern done by setCanonicalName of ObjectName.

Here is an example which shows the problem in one process:
private static String keyname = "iiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiii";

   private static List<ObjectName> names = new LinkedList<ObjectName>();

   private static long counter = 0;

   private static MBeanServer mbeanServer;

   final static MBean mbean = new MBean();

   public static void main (final String[] args)
      throws IOException, InstanceNotFoundException, MalformedObjectNameException, NullPointerException, InterruptedException

   {
      // Init of process 1
      mbeanServer = ManagementFactory.getPlatformMBeanServer();
      // End of init process 1

      // This happens in process 2
      final String address = "service:jmx:rmi:///jndi/rmi://:15431/jmxrmi";
      final JMXServiceURL serviceURL = new JMXServiceURL(address);
      final JMXConnector connector = JMXConnectorFactory.connect(serviceURL, null);
      final MBeanServerConnection mBeanServerConnection = connector.getMBeanServerConnection();
      mBeanServerConnection.addNotificationListener(new ObjectName("JMImplementation:type=MBeanServerDelegate"),
               new NotificationListener()
               {
                  public void handleNotification (final Notification notification, final Object handback)
                  {

                     try
                     {
                        final ObjectName name = ((MBeanServerNotification) notification).getMBeanName();
                        final String type = notification.getType();
                        if (type.equals(MBeanServerNotification.REGISTRATION_NOTIFICATION))
                        {
                           mBeanServerConnection.addNotificationListener(name, this, null, null);

                        }
                        else if (type.equals(MBeanServerNotification.UNREGISTRATION_NOTIFICATION))
                        {
                           // The next line is useless it throws a ListenerNotFoundException
                           mBeanServerConnection.removeNotificationListener(name, this);
                        }
                     }
                     catch (final InstanceNotFoundException ex)
                     {
                        ex.printStackTrace();
                     }
                     catch (final IOException ex)
                     {
                        ex.printStackTrace();
                     }
                     catch (final ListenerNotFoundException ex)
                     {// No exception handling because the exception is allways thrown if removeNotificationListener(name, this) is called
                     }

                  }
               }, null, null);
      // End of process2

      // This happens in process 1
      for (int i = 0; i < 100000; i++)
      {
         registerMBean(); // Register some MBeans to avoid InstanceNotFoundException when registering the NotificationListener
      }
      while (true)
      {
         try
         {
            registerMBean();
            mbeanServer.unregisterMBean(names.remove(0)); // Remove oldest MBean
            if (counter % 10000 == 0)
            {
               System.out.print("*");
            }
         }
         catch (final MBeanRegistrationException ex)
         {
            ex.printStackTrace();
         }
         catch (final InstanceNotFoundException ex)
         {
            ex.printStackTrace();
         }
      }

   }

   private static void registerMBean ()
      throws MalformedObjectNameException
   {

      final ObjectName name = new ObjectName("a.b.c.", keyname + counter, "ad");

      counter++;
      names.add(name);
      try
      {
         mbeanServer.registerMBean(mbean, name);
      }
      catch (final MBeanRegistrationException ex)
      {
         ex.printStackTrace();
      }
      catch (final InstanceAlreadyExistsException ex)
      {
         ex.printStackTrace();
      }
      catch (final NotCompliantMBeanException ex)
      {
         ex.printStackTrace();
      }
      return;
   }

   private static final class MBean
      implements DynamicMBean, NotificationBroadcaster
   {

      public MBean ()
      {
      }

      public Object getAttribute (final String attribute)
         throws AttributeNotFoundException, MBeanException, ReflectionException
      {
         return null;
      }

      public AttributeList getAttributes (final String[] attributes)
      {
         return null;
      }

      public MBeanInfo getMBeanInfo ()
      {
         return new MBeanInfo(DynamicMBean.class.getCanonicalName(), "", null, null, null, null);
      }

      public Object invoke (final String actionName, final Object[] params, final String[] signature)
         throws MBeanException, ReflectionException
      {
         return null;
      }

      public void setAttribute (final Attribute attribute)
         throws AttributeNotFoundException, InvalidAttributeValueException, MBeanException, ReflectionException
      {
      }

      public AttributeList setAttributes (final AttributeList attributes)
      {
         return null;
      }

      public void addNotificationListener (final NotificationListener listener, final NotificationFilter filter,
                                           final Object handback)
      {
      }

      public MBeanNotificationInfo[] getNotificationInfo ()
      {
         return null;
      }

      public void removeNotificationListener (final NotificationListener listener)
         throws ListenerNotFoundException
      {
         System.out.print("-");
      }
   }
Started with:
-Dcom.sun.management.jmxremote.authenticate=false 
-Dcom.sun.management.jmxremote.ssl=false
-Dcom.sun.management.jmxremote.port=15431
Does anyone have a workaround for this? Have I overlooked a fault or is this a known bug? I searched for it but could not find one.

I have to use the jre1.6.0_05.

Thank you for your input.

Edited by: Domi27 on Sep 14, 2009 10:11 PM