【问题标题】:Java: GarbageCollectorMXBean getCollectionCount throws java.io.IOException: The client has been closedJava:GarbageCollectorMXBean getCollectionCount 抛出 java.io.IOException:客户端已关闭
【发布时间】:2014-08-18 16:12:57
【问题描述】:

我正在编写一个 Java 应用程序,我使用 Java GarbageCollectorMXBean API 定期(每 5 秒)获取收集计数。下面是我为完成任务而编写的程序。

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

}

程序运行良好,但有时它会在每个循环中重复出现以下 IOException。

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)

查看代码,任何异常都会在 catch 块中捕获,其中所有字段都将初始化为 null,并且在下一个循环中,所有字段都将重新初始化。但是,查看日志,一旦异常开始出现,我只能在每个循环中的getCollectionCount() 调用中获得上述异常。我想知道即使对象被重新初始化,每次我得到同样的异常。

我正在从上述信息中查看以下内容

  1. 在所有情况下,我们都会在上述场景中得到这个异常java.io.IOException: The client has been closed.。我知道,如果我们调用jmxConnector.close() 然后使用已经创建的garbageCollectorMXBean 对象来获取集合计数,我们就会得到这个。但我的代码不遵循这条路。
  2. 对于上述问题,jmxserver 远程 JMX 服务器有贡献吗?我尝试通过停止/重新启动远程 JMX 服务器来重现,但无法做到。

【问题讨论】:

  • 您尝试在 Oracle VM 或 OpenJDK 上运行它吗?也许 IBM 的 vm 在调用 ManagementFactory.newPlatformMXBeanProxy(mbsc, GC_NAME,GarbageCollectorMXBean.class) 时确实返回 GarbageCollectorMXBean 的新实例。这可以解释无休止的java.io.IOException: The client has been closed,因为在旧对象上调用它会无休止地产生这个异常。在 Oracle VM 上,我看到该实例是新的。
  • 您能找出问题所在吗?我遇到了类似的例外情况

标签: java garbage-collection jmx mxbean


【解决方案1】:

从堆栈跟踪最后一行来看:

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

看来问题出在代码行上

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

@raghavendra ,当您从 "JMXConnector" 获取 "MBeanServerConnection" 对象时,您应该按该顺序关闭对象/取消它们,即将您的代码更改为

if (jmxConnector != null)
            {
                try
                {
                    mbsc = null;    //...object handle assigned null before closing the connector 
                    jmxConnector.close();
                } catch (IOException ioe) {}
                jmxConnector = null;
            }

【讨论】:

  • 实际上第 48 行在 mbsc = jmxConnector.getMBeanServerConnection(); 行。不要计算给定示例程序中的行数。这只是一个样本。如果问题出在那个 try catch 块中,那么我想知道为什么这个异常会在某个未知的时间发生?它在大多数情况下都可以正常工作,但突然开始出现异常。但同时,如果我通过 Jconsole 连接到同一个 JVM,我可以看到 bean 'java.lang:name=MarkSweepCompact,type=GarbageCollecto' 并执行收集计数,但我的程序继续给出异常。非常困惑。
  • 如果 IOException 发生在“mbsc = jmxConnector.getMBeanServerConnection()”行,那么您应该在尝试获取 mbeanServerConnection 之前测试 jmxConnetor 的有效连接。如果问题是随机的并且不是确定性的,那么它就是网络问题。因此,如果您发现对象 jmxConnector not valid ,代码应该再等待 5-10 秒,然后重试。
猜你喜欢
  • 2017-06-06
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2021-01-09
  • 1970-01-01
  • 2020-09-10
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多