5

GarbageCollectorMXBeanJava API を使用して定期的な間隔 (5 秒ごと) でコレクション数を取得するJava アプリケーションを作成しています。以下は、タスクを実行するために私が書いたプログラムです。

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)

コードを見ると、すべてのフィールドが null に初期化され、次のループですべてのフィールドが再初期化される catch ブロックで例外がキャッチされます。getCollectionCount()しかし、ログを見ると、例外が発生し始めると、すべてのループの呼び出しでのみ例外が発生します。同じ例外が発生するたびに、オブジェクトが再初期化されても不思議ではありません。

上記の情報から次のことを見ています

  1. どのような場合でもjava.io.IOException: The client has been closed.、上記のシナリオでこの例外が発生します。呼び出しjmxConnector.close()て、既に作成されたgarbageCollectorMXBeanオブジェクトを使用してコレクション数を取得すると、これが得られます。しかし、私のコードはその道をたどりません。
  2. 上記の問題について、jmxserverリモート JMX サーバーは貢献していますか? リモートJMXサーバーを停止/再起動して再現しようとしましたが、できませんでした。
4

1 に答える 1

0

スタックトレースの最後の行から判断すると:

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;
            }
于 2014-09-29T16:07:48.900 に答える