5

I am writing a Java application where I am using Java GarbageCollectorMXBean APIs to get the collection count at regular intervals (for every 5 seconds). Below is the program I have written to do the task.

import java.io.IOException;
import java.lang.management.GarbageCollectorMXBean;
import java.lang.management.ManagementFactory;
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 JMXTest {
    public static final String GC_NAME = "java.lang:name=MarkSweepCompact,type=GarbageCollector";
    private static GarbageCollectorMXBean garbageCollectorMXBean;
    private static JMXConnector jmxConnector;
    private static MBeanServerConnection mbsc;

    public static void main(String[] args) throws Exception {
        String rmiHostname = "jmxserver";
        String defaultUrl = "service:jmx:rmi:///jndi/rmi://" + rmiHostname + ":1999/jmxrmi";
        JMXServiceURL jmxServiceURL = new JMXServiceURL(defaultUrl);

        Map<String,Object> jmxCredentials = new HashMap<String,Object>();
        String[] credentials = new String[]{"jmxusername", "jmxpassword"};
        jmxCredentials.put("jmx.remote.credentials", credentials);

       boolean run = true;
       while(run){
         try {
            if(garbageCollectorMXBean == null){
                if (mbsc == null){
                    jmxConnector = JMXConnectorFactory.connect(jmxServiceURL, jmxCredentials);
                    mbsc = jmxConnector.getMBeanServerConnection();
                }
                garbageCollectorMXBean = ManagementFactory.newPlatformMXBeanProxy(mbsc, GC_NAME,GarbageCollectorMXBean.class);
            }
            long count = garbageCollectorMXBean.getCollectionCount();
            System.out.println("Garbage Collector count = " + count);
        } catch (Exception e) {
            e.printStackTrace();
            garbageCollectorMXBean = null;
            if (jmxConnector != null)
            {
                try
                {
                    jmxConnector.close();
                } catch (IOException ioe) {}
                jmxConnector = null;
            }
            mbsc = null;
        }
        Thread.currentThread().sleep(5000);
    }
}

}

The program runs fine, but sometimes it starts giving following IOException repeatedly in every loop.

Exception in thread "main" java.io.IOException: The client has been closed.
at java.util.TimerThread.run(Timer.java:505)
at com.sun.jmx.remote.internal.ClientCommunicatorAdmin.restart(ClientCommunicatorAdmin.java:94)
at com.sun.jmx.remote.internal.ClientCommunicatorAdmin.gotIOException(ClientCommunicatorAdmin.java:54)
at javax.management.remote.rmi.RMIConnector$RMIClientCommunicatorAdmin.gotIOException(RMIConnector.java:1470)
at javax.management.remote.rmi.RMIConnector$RemoteMBeanServerConnection.getAttribute(RMIConnector.java:906)
at com.ibm.lang.management.OpenTypeMappingIHandler$6.run(OpenTypeMappingIHandler.java:506)
at java.security.AccessController.doPrivileged(AccessController.java:330)
at com.ibm.lang.management.OpenTypeMappingIHandler.invokeAttributeGetter(OpenTypeMappingIHandler.java:501)
at com.ibm.lang.management.OpenTypeMappingIHandler.invoke(OpenTypeMappingIHandler.java:121)
at com.sun.proxy.$Proxy112.getCollectionCount(Unknown Source)
at JMXTest.main(JMXTest.java:48)

Looking at the code, any exception will get caught in catch block where all fields will be initialized to null and in the next loop all the fields will be reinitialized. But, looking at the logs, once the exception starts coming, I get above exception only at getCollectionCount() call in every loop. I wonder even though the objects are re-initialized, every time I get same exception.

I am looking at following things from the above information

  1. In what all cases, we get this exception java.io.IOException: The client has been closed. in the above scenario. I know, if we call jmxConnector.close() and then use the already created garbageCollectorMXBean object to get the collection count, we get this. But my code does not follow that path.
  2. For the above issue, does jmxserver remote JMX server contributes? I tried to reproduce by stopping/restarting the remote JMX server, but could not do it.
Nathan Tuggy
  • 2,237
  • 27
  • 30
  • 38
Raghavendra Nilekani
  • 396
  • 2
  • 10
  • 22
  • Did you try to run it on Oracle VM or OpenJDK ? Maybe IBM's vm does _not_ return new instance of GarbageCollectorMXBean when calling to `ManagementFactory.newPlatformMXBeanProxy(mbsc, GC_NAME,GarbageCollectorMXBean.class)`. This would explain endless `java.io.IOException: The client has been closed` since calling it on old object produces this exception endlessly. On Oracle VM as I see the instance is new. – walkeros Sep 26 '14 at 08:57
  • Were you able to figure out the problem? I am getting similar exceptions – Amm Sokun Nov 12 '15 at 09:13

1 Answers1

0

judging from the stack trace last line :

at com.sun.proxy.$Proxy112.getCollectionCount(Unknown Source)
at JMXTest.main(JMXTest.java:48)

it seems the problem is with line of code

if (jmxConnector != null)
            {
                try
                {
                    jmxConnector.close();
                } catch (IOException ioe) {}
                jmxConnector = null;   //...line no.48
            }
            mbsc = null;    //......this is probably causing the issue

@raghavendra , as you acquire the "MBeanServerConnection" object from the "JMXConnector" , you should close the objects / nullify them in that order i.e. change your code to

if (jmxConnector != null)
            {
                try
                {
                    mbsc = null;    //...object handle assigned null before closing the connector 
                    jmxConnector.close();
                } catch (IOException ioe) {}
                jmxConnector = null;
            }
vreddy
  • 173
  • 1
  • 9
  • Actually the line number 48 is at line mbsc = jmxConnector.getMBeanServerConnection();. Don't count the lines in the give sample program. It is just a sample. If the issue is in that try catch block, then I am wondering why would this exception occur at some unknowing time ? It works fine most of the time and suddenly starts giving exception. But at the same time if I connect to the same JVM through Jconsole, I can see the bean 'java.lang:name=MarkSweepCompact,type=GarbageCollecto' and execute the collection count, but my program kept on gives exception. Very much confused. – Raghavendra Nilekani Sep 29 '14 at 17:42
  • if the IOException is occuring at line "mbsc = jmxConnector.getMBeanServerConnection()", then you should be testing the jmxConnetor for a valid connection before trying to get the mbeanServerConnection. if the issue is random and not deterministic, then its a network issue . So if you find the object jmxConnector not valid , the code should just wait for another 5-10 secs and try again. – vreddy Sep 30 '14 at 14:05