先週,試しにアクセスしてみたMXBeanはすべてJSR-174 Monitoring and Management Specification for the Java Virtual Machineで定義されたものです。

このJSR-174はシステムの運用・保守においてきわめて重要なAPIだと筆者は確信しています。

システムの運用中に,メモリーの使用状況やスレッド間のデッドロックの有無,CPUの使用量などをモニタリングできるということは,管理業務を行う人にとってどれほど手助けになるでしょうか。

特に,24時間,週7日間ノンストップで動作するようなシステムではなおさらです。

幸いにもJavaで構築されたシステムはすべてJVM上で動作します。つまり,メモリー使用量などの管理に必要な情報を取得するために独自に作り込む必要はまったくなく,JVMに仕込まれたMXBeanを使えば簡単に取得できるのです。

それもシステムを動作させているプラットフォームに依存せずに行なうことができます。

もちろん,個々のシステムに特有の情報に関してはMBeanを独自に定義して管理を行なうことは必要ですが,必要最低限の情報は何もしなくても得ることができるのはJavaの利点の一つでもあります。

今までJavaの利点としてWrite Once, Run Anywhereとかセキュリティなどいろいろな点が挙げられていましたが,これからはJavaの最大の利点は管理の容易性にあるといわれるかもしれません。

ところで,MXBeanを使わずともメモリー使用量などを取得することは可能です。たとえば,Runtime#freeMemoryメソッドは空きメモリー量を返します。しかし,これでは不十分です。

また,これもJavaの利点だと思いますが,Javaではプロファイリングのためのインタフェースが規定されています。J2SE 5.0以前はJVMPI (Java Virtual Machine Profile Interface),J2SE 5.0以降はJVMTI (Java Virtual Machine Tool Interface)となります。

これらのインタフェースを使用することでJVMの詳細な情報を取得できます。しかし,JVMTI/JVMPIには重要な欠点が一つあります。Javaのプロファイラを使用してみればすぐにわかるのですが,これらのインタフェースを使用して得られる情報は膨大なため,処理が重いのです。

これでは,運用と共に用いるということはできません。

そこで登場したのが,管理のために必要なものに機能を絞って,動作を軽くしたJSR-174 Monitoring and Management Specification for the Java Virtual Machineなのです。

JSR-174を使用すれば,24時間/週7日のシステムを運用しながらでも,パフォーマンス低下を起こさずに管理に必要な情報を参照できます。

MXBeanの種類

ではJSR-174ではどのような情報にアクセスできるのでしょう。JSR-174で定義されているMXBeanは次の9種類です。

表1 MXBean

名称 説明
OperatingSystemMXBean OSに関するMXBean
RuntimeMXBean クラスパスや起動時オプションなどのランタイムに関するMXBean
CompilationMXBean JITに関するMXBean
ClassLoadingMXBean クラスローディングに関するMXBean
ThreadMXBean スレッド数やスレッドの状態などスレッド全般に関するMXBean
MemoryMXBean メモリーに関する概要を示すMXBean
MemoryManagerMXBean メモリーの管理に関するMXBean
GarbageCollectorMXBean GCに関するMXBean
MemoryManagerMXBeanの派生MXBean
MemoryPoolMXBean 用途別に用意されるメモリー・プールに関するMXBean

表2 スレッドに関して取得できる主な情報

項目
現在のスレッド数
スレッド数のピーク
カレント・スレッドのCPU時間
各スレッドのID,名称
各スレッドの状態
スタック・トレース
デッドロックの有無

表3 メモリーに関して取得できる主な情報

項目
各領域の名称,タイプ(ヒープ/非ヒープ)
各領域のメモリー使用量
各領域のメモリー使用量の最大値
各領域のメモリー使用量のピーク
各領域のGC後のメモリー使用量
GCにかけた時間
最後のGCの開始,終了時間
最後のGCの前後のメモリー使用量

これらはすべてjava.lang.managementパッケージで定義されています。また,J2SE 5.0ではJSR-174で定義されている以外の情報(例えばGCの情報など)を取得できるように拡張されています。

これらのMXBeanの中で特に重要なのが,スレッドに関するThreadMXBeanと,メモリーに関するMemoryMXBean,MemoryPoolMXBean,GarbageCollectionMXBeanの四つのMXBeanです。

ThreadMXBeanはスレッドに関するプロパティを保持しています。一例を挙げると,現在のスレッド数,スレッド数のピーク,カレント・スレッドのCPU時間,スレッドIDなどがあります。

個々のスレッドの情報に関してはThreadInfoクラスを使用して表されます。ThreadInfoクラスではスレッドの名前,状態(動作中,待ち,スリープなど),スタック・トレースなどを保持しています。

マルチスレッドのアプリケーションでは,まれにデッドロックを引き起こすことがありますが,ThreadMXBeanではfindMonitorDeadlockThreadsメソッドが定義されており,デッドロックであるかどうかを調べることができます。

さらに,デッドロックしているときに,ブロックしてからどのくらいの時間が経過しているか,ロックしているスレッドのIDなどのブロッキングに関する情報もThreadInfoオブジェクトから取得することができます。

また,ThreadInfoオブジェクトのスタック・トレースを使えば,実際にどの処理でブロックされているかを調べることが可能です。

MemoryMXBeanはメモリー使用量に関してのプロパティを保持しています。MemoryMXBeanオブジェクトはヒープを表すものと非ヒープを表すものの二つがインスタンス化されています。それぞれのメモリーの最大値,現在の使用量などを知ることができます。

より詳細なメモリーの使用状況を調べるにはMemoryPoolMXBeanを使用します。

MemoryPoolMXBeanはメモリー領域ごとに割り当てられており,前述したEdenやTenuredなどの領域に対応してオブジェクトが作られます。

それぞれの領域の最大値や使用量だけでなく,GCが行なわれた後の使用量や,使用量のピーク値なども保持されています。

さらに,MemoryPoolMXBeanでは領域の使用量に閾値を設定することができます。この閾値を超えると,(MemoryPoolMXBeanではなく)MemoryMXBeanがノティフィケーションを発生させます。

JSR-174での定義では,GarbageCollectionMXはGCの回数とGCにかかった時間を示すだけです。しかし,J2SE 5.0では独自の拡張が行なわれており,一番最後に行なわれたGCの情報を調べることができます。たとえば,GCの開始時間と終了時間,GC前後のメモリー使用量などを参照することができます。

どうですか,これだけ調べられれば運用で必要な情報はかなりカバーできるのではないでしょうか。さらに,メモリーのノティフィケーションを使用すれば,警戒域に入ったときに自動的に知らせてくれます。

これで,ソフトウエア管理の基本的なところは押さえられるはずです。後は,個々のシステムに応じたMBeanを定義して使うようにすれば完璧です。

そこで,来月は独自にMBeanもしくはMXBeanを定義する方法について紹介していきます。

著者紹介 櫻庭祐一

横河電機の研究部門に勤務。同氏のJavaプログラマ向け情報ページ「Java in the Box」はあまりに有名