JmxでリモートJVMからMxBeanを取得するサンプル
追記 2014-03-30
取り敢えず作ってみた。
Jmxで取得したJavaVMメモリ使用状況をcsvに出力するWindowsサービス(中の人はJava)を書いた - ka-ka_xyzの日記
最近PHPの泥沼(いやPHPをDisっているわけではなく、PHPで書かれたレガシーコードが激しく腐海と言う意)に漬かっていてどうにもJavaで何か書きたくなったので突発企画。
リモートに有るJavaVMからJmxのMxBeanを取ってきて、JavaVMのヒープ領域使用状況を取得します。ヒープ領域の説明やGCとの絡みはこの辺参照。
Java Review:JavaVMのメモリ管理をマスターする (1/2) - ITmedia エンタープライズ
Jmxの接続先(監視対象)としてJava6,7で動作確認。監視対象のJvmを起動する時に下記オプションを追加してください。
-Dcom.sun.management.jmxremote.port=<ポート番号> -Dcom.sun.management.jmxremote.authenticate=false -Dcom.sun.management.jmxremote.ssl=false
今回のソースでは認証やSSLには対応してません。
package jp.gr.java_conf.ka_ka_xyz.example; import java.io.IOException; import java.lang.management.ManagementFactory; import java.lang.management.MemoryPoolMXBean; import java.text.SimpleDateFormat; import java.util.ArrayList; import java.util.Date; import java.util.List; import javax.management.MBeanServerConnection; import javax.management.remote.JMXConnector; import javax.management.remote.JMXConnectorFactory; import javax.management.remote.JMXServiceURL; /** * リモートJVMからMxBeanを取得するサンプル * */ public class Example{ private static MBeanServerConnection remote = null; public static void main(String[] args) throws Exception { //接続先ホスト名(ベタ書きやっつけ仕事) String host = "localhost"; //jmxポート番号(ベタ書きやっつけ仕事) int port = 17999; final String serviceUrlStr = "service:jmx:rmi:///jndi/rmi://" + host + ":" + port + "/jmxrmi"; final JMXServiceURL target = new JMXServiceURL(serviceUrlStr); JMXConnector connector = null; try { connector = JMXConnectorFactory.connect(target); // リモートJvmへのコネクション作成 remote = connector .getMBeanServerConnection(); } catch (IOException e) { //コネクションエラー発生時の処理(手抜き) System.err.println("filed to connect: " + target.toString()); e.printStackTrace(); System.exit(-1); } //Survivor領域についてのPool名 final String survivorSpaceMemoryPoolMxbeanName = "PS Survivor Space"; //Eden領域についてのPool名 final String edenSpaceMemoryPoolMxbeanName = "PS Eden Space"; //Old Gen領域についてのPool名 final String oldGenSpaceMemoryPoolMxbeanName = "PS Old Gen"; //Perm Gen領域についてのPool名 final String permGenSpaceMemoryPoolMxbeanName = "PS Perm Gen"; //Code Cache領域についてのPool名 final String codeCacheSpaceMemoryPoolMxbeanName = "Code Cache"; List<MemoryPoolMXBean> beans = new ArrayList<MemoryPoolMXBean>(); //MxBeanを取得 beans.add(getMemoryPoolMxBean(survivorSpaceMemoryPoolMxbeanName)); beans.add(getMemoryPoolMxBean(edenSpaceMemoryPoolMxbeanName)); beans.add(getMemoryPoolMxBean(oldGenSpaceMemoryPoolMxbeanName)); beans.add(getMemoryPoolMxBean(permGenSpaceMemoryPoolMxbeanName)); beans.add(getMemoryPoolMxBean(codeCacheSpaceMemoryPoolMxbeanName)); //参考情報出力 SimpleDateFormat sdf = new SimpleDateFormat("yyyy.MM.dd_HH:mm:ss z"); System.out.println("datetime: " + sdf.format(new Date())); System.out.println("Jmx Url: " + serviceUrlStr); for(MemoryPoolMXBean bean : beans) { if(bean == null){continue;} System.out.println(bean.getName() + ": " + bean.getUsage()); //下記のようにMemoryUsageインスタンスを取得して個別の値を取得することも可能 //MemoryUsage usage = bean.getUsage(); } if(connector != null){connector.close();} } /** * MxBean名からMemoryPoolMXBeanインスタンスを取得します。 * @param beanName MxBean名 * */ private static MemoryPoolMXBean getMemoryPoolMxBean(String beanName) throws IOException{ MemoryPoolMXBean mpmxbean = ManagementFactory.newPlatformMXBeanProxy( remote, ManagementFactory.MEMORY_POOL_MXBEAN_DOMAIN_TYPE + ",name=" + beanName, MemoryPoolMXBean.class); return mpmxbean; } }
今気づいたけど、一応localhostじゃなくてリモートサーバーのJvm呼び出しといた方が良かったかな。理屈の上ではおkなはずなんで、検証は取り敢えず後で。
実行結果はこんな感じ
datetime: 2014.03.23_01:48:20 JST Jmx Url: service:jmx:rmi:///jndi/rmi://localhost:17999/jmxrmi PS Survivor Space: init = 8388608(8192K) used = 262144(256K) committed = 262144(256K) max = 262144(256K) PS Eden Space: init = 50331648(49152K) used = 15273856(14915K) committed = 42598400(41600K) max = 1059258368(1034432K) PS Old Gen: init = 134217728(131072K) used = 12752952(12454K) committed = 134217728(131072K) max = 2147483648(2097152K) PS Perm Gen: init = 21757952(21248K) used = 25684856(25082K) committed = 25690112(25088K) max = 85983232(83968K) Code Cache: init = 2555904(2496K) used = 2484416(2426K) committed = 2555904(2496K) max = 50331648(49152K)
後はWindowsサービスに組み込んだりcsvへの出力を書いたりすればお手軽なヒープ使用状況確認ツールが作れそう(jconsoleだとサービス起動出来ないから不便なんだよなあ)。