Raghavendra Nilekani
Raghavendra Nilekani

Reputation: 406

Java: GarbageCollectorMXBean getCollectionCount throws java.io.IOException: The client has been closed

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.

Upvotes: 5

Views: 1844

Answers (1)

vreddy
vreddy

Reputation: 173

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;
            }

Upvotes: 0

Related Questions