今月も引き続き,VisualVMについて紹介していきます。

 前回,VisualVMのプラグインを自作する方法について紹介しました。とはいうものの,プラグインで新たなタブを作成しただけで終わってしまいました。

そこで,今回はターゲットとなるアプリケーションから情報を取得し,プラグインで作成したタブに表示する方法を紹介していきます。

アプリケーションからの情報取得手法

アプリケーションから情報を収集するには複数の方法があります。主な手法を以下に列挙しました。

  • JMX (Java Management Extensions)
  • JVMTI (Java Virtual Machine Tool Interface)
  • Attach API
  • DTrace/BTrace

JMXはこの連載では何度も取りあげているソフトウエア管理のためのAPIです。ヒープのサイズや,スレッドの状態などを調べることはもちろん,MBean(Managed Bean)を自作することで個々のアプリケーションに特有な情報も収集することが可能です。

JVMTIはプロファイラとデバッガのためのインタフェースです。JDK 5.0以前はプロファイラ用のJVMPIとデバッガ用のJVMDIが使われていました。しかし,JDK 5.0でこの2つのインタフェースが統合されJVMTIになりました。

Attach APIはJava SE 6完全攻略第10回で紹介した,Instrument APIもしくはJVMTIで記述したエージェントをターゲットのJava VMにロードするためのAPIです。エージェント通信することで,アプリケーションの情報を収集することができます。

DTraceはSolarisとMacで使用できるトレースツールです。DTraceはJavaだけでなく,OSのシステムコールなど,汎用に使用することができます。一方のBTraceはJavaに特化したトレースツールです。

VisualVMは,これら複数の手法のいずれも使用することができますが,今回は,VisualVMがAPIを提供しており,簡単に使用できることからJMXを使用することにします。

JMXによるアプリケーションからの情報取得

JMXを使用してアプリケーションに接続するのは,いくつものステップがあり,ちょっと面倒です。

大まかに書き出してみると,次のようなステップとなります。

  1. ターゲットとなるアプリケーションのURLをJMXServiceURLクラスで記述する
  2. JMXConnectorFactoryクラスを用いて,1で記述したURLからJMXConnectorオブジェクトを生成し,アプリケーションに接続する
  3. MBeanServerに対応するMBeanServerConnectionオブジェクトをJMXConnectorオブジェクトから取得する
  4. MBeanServerInvocationHandlerクラスを使用してMBeanServerConnectionオブジェクトからMBeanのプロキシを生成する
  5. MBeanのプロキシに対し,情報の収集,操作を行う

この流れはMXBeanを扱う場合でも同じです。

しかし,VisualVMはヒープやスレッドの情報を取得するためにJMXでアプリケーションに接続しています。このため,接続の部分までを省略することができます。また,MXBeanを扱う場合,プロキシを生成する部分も行ってくれます。

たとえば,MemoryXBeanを扱うのであれば,次のようなコードを記述するだけです。

Application application = ...
    
JmxModel jmx = JmxModelFactory.getJmxModelFor(application);
JvmMXBeans mxbeans = JvmMXBeansFactory.getJvmMXBeans(jmx);

MemoryMXBean memoryMXBean = mxbeans.getMemoryMXBean();

com.sun.tools.visualvm.application.ApplicationオブジェクトはVisualVMから渡されるので,自分で用意する必要はありません。

com.sun.toools.visualvm.tools.jmx.JmxModelクラスがJMXでのアプリケーション接続を抽象化したクラスです。そして,com.sun.toools.visualvm.tools.jmx.JvmMXBeansクラスが,MXBeansを扱うプラットフォームMBeanServerに相当するクラスです。

MemoryMXBeanオブジェクトはJvmMXBeansオブジェクトから直接取得できるので,プロキシ生成などを意識することなく使用することができます。

しかし,たとえば接続が切れたアプリケーションに対してMXBeanのプロキシから操作を行うとjava.lang.reflect.UndeclaredThrowableException例外が発生するなど,完全にプロキシであることを意識しないというわけにはいかないようです。

JMXでの接続の方法がわかったので,さっそく前回作成したプラグインに組み込んでいきましょう。