Java Management Extensions の主要どころの簡単なまとめです。
- RuntimeMXBean
- CompilationMXBean
- OperatingSystemMXBean
- MemoryMXBean
- MemoryPoolMXBean
- ThreadMXBean
- ClassLoadingMXBean
- GarbageCollectorMXBean
- サンプル
- Java1.6 時代のCPU使用率
RuntimeMXBean
ランタイム関連情報の取得。
RuntimeMXBean runtimeMx = ManagementFactory.getRuntimeMXBean();
以下のような情報が取得できます。
メソッド | 出力例 | 説明 |
---|---|---|
getVmName() | Java HotSpot(TM) 64-Bit Server VM | VM名 |
getVmVersion() | 25.102-b14 | VMバージョン |
getVmVendor() | Oracle Corporation | VMベンダ名 |
getSpecName() | Java Virtual Machine Specification | JVM仕様名 |
getSpecVersion() | 1.8 | JVM仕様のバージョン |
getSpecVendor() | Oracle Corporation | JVM仕様のベンダ名 |
getManagementSpecVersion() | 1.2 | 管理インタフェースの仕様のバージョン |
getName() | 95264@hostname | 実行しているJVMの名前。sunの実装では@より前がPID |
new Date(getStartTime()).toString() | Mon Feb 01 00:00:00 JST 2017 | 起動日時 |
getUptime() | 起動してからの経過時間(ms) | |
getInputArguments().toString() | [-Dfile.encoding=UTF-8, ...] | 入力引数 |
getClassPath() | /.../jre/lib/charsets.jar:/... | システムクラスローダーが使用するクラスパスの文字列 |
getLibraryPath() | /.../Java/Extensions:/... | ライブラリパス |
getBootClassPath() | /.../lib/resources.jar:/... | ブートストラップクラスローダが使用するクラスパスの文字列 |
isBootClassPathSupported() | ブートストラップクラスパスをサポートするか |
CompilationMXBean
CompilationMXBean compilationMx = ManagementFactory.getCompilationMXBean(); if (compilationMx != null) { // ... }
環境によってはnullが帰る場合がありますので念のためnullチェックをしておいた方が良いです。
以下のような情報が取得できます。
メソッド | 出力例 | 説明 |
---|---|---|
getName() | HotSpot 64-Bit Tiered Compilers | JITコンパイラ名 |
getTotalCompilationTime() | JITコンパイルの累積経過時間(ms) | |
isCompilationTimeMonitoringSupported() | コンパイル時間の監視をサポートするか |
OperatingSystemMXBean
OS関連情報です。
java.lang.management.OperatingSystemMXBean
はあまり情報取れないので、com.sun.management.OperatingSystemMXBean
にキャストして使うことが多いです。
OperatingSystemMXBean osMx = (OperatingSystemMXBean) ManagementFactory.getOperatingSystemMXBean();
以下のような情報が取得できます。
メソッド | 出力例 | 説明 |
---|---|---|
getName() | Mac OS X | OS名 |
getVersion() | 10.12.2 | OSバージョン |
getArch() | x86_64 | OSアーキテクチャ |
getAvailableProcessors() | 8 | プロセッサ数 |
getCommittedVirtualMemorySize() | 6.2 GB | 利用可能な仮想メモリー容量(byte) |
getSystemCpuLoad() | 0.1 | システム全体のCPU使用率(0.0〜1.0の値) |
getSystemLoadAverage() | 5.51... | 最後の1分のシステム全体ロードアベレージ |
getTotalPhysicalMemorySize() | 8.6 GB | 物理メモリーの合計容量(byte) |
getFreePhysicalMemorySize() | 58.0 MB | 空き物理メモリー容量(byte) |
getTotalSwapSpaceSize() | 5.4 GB | スワップ空間の合計容(byte) |
getFreeSwapSpaceSize() | 1.5 GB | 空きスワップ空間容量(byte) |
getProcessCpuLoad() | 0.1 | VMプロセスのCPU使用率(0.0〜1.0の値) |
getProcessCpuTime() | 478183000 | VMプロセスが使用したCPU時間(ns) |
なお、出力例のバイト文字は以下の要領で整形したものです(実際はバイト値がlongで出力されます)。
public static String prettyBytes(long bytes, boolean si) { int unit = si ? 1000 : 1024; if (bytes < unit) return bytes + " B"; int exp = (int) (Math.log(bytes) / Math.log(unit)); String pre = (si ? "kMGTPE" : "KMGTPE").charAt(exp-1) + (si ? "" : "i"); return String.format("%.1f %sB", bytes / Math.pow(unit, exp), pre); }
MemoryMXBean
メモリの概要です。
MemoryMXBean memoryMx = ManagementFactory.getMemoryMXBean();
以下のような情報が取得できます。
メソッド | 説明 |
---|---|
getObjectPendingFinalizationCount() | ファイナライズ保留オブジェクト数 |
getHeapMemoryUsage() | ヒープ使用量 |
getNonHeapMemoryUsage() | ノンヒープ使用量 |
isVerbose() | 詳細出力が有効か |
setVerbose(boolean value) | 詳細出力の有効/無効 |
gc() | GCを実行 |
MemoryUsage からはもう少し詳細な情報が取得できます。
MemoryUsage memoryUsage = memoryMx.getHeapMemoryUsage();
以下の情報を得ることができます。
メソッド | 出力例 | 説明 |
---|---|---|
getCommitted() | 129.0 MB | |
getInit() | 134.2 MB | 初期ヒープ容量 |
getMax() | 1.9 GB | 利用可能なヒープ容量 |
getUsed() | 4.1 MB | 現在利用しているヒープ容量 |
MemoryPoolMXBean
MemoryMXBean では概要の情報でしたが、MemoryPoolMXBeanでは各種のメモリプールの詳細を見ることができます。
List<MemoryPoolMXBean> memoryPoolMxs = ManagementFactory.getMemoryPoolMXBeans(); for (MemoryPoolMXBean memoryPoolMx : memoryPoolMxs) { System.out.println(memoryPoolMx.getName() + ", " + Arrays.deepToString(memoryPoolMx.getMemoryManagerNames())); MemoryUsage mu = memoryPoolMx.getUsage(); // ... }
以下のようなメモリプール達が出力されました。
Code Cache, [CodeCacheManager] Metaspace, [Metaspace Manager] Compressed Class Space, [Metaspace Manager] PS Eden Space, [PS MarkSweep, PS Scavenge] PS Survivor Space, [PS MarkSweep, PS Scavenge] PS Old Gen, [PS MarkSweep]
MemoryPoolMXBean から、または MemoryUsage などを経由して各種メモリ関連の情報を取得することができます。
ThreadMXBean
スレッド関連です。
ThreadMXBean thread = (com.sun.management.ThreadMXBean) ManagementFactory.getThreadMXBean();
以下のような情報が取得できます。
メソッド | 出力例 | 説明 |
---|---|---|
getThreadCount() | 6 | ライブスレッド数 |
getDaemonThreadCount() | 4 | デーモンスレッド数 |
getPeakThreadCount() | 6 | 起動後からのピークスレッド数 |
getTotalStartedThreadCount() | 7 | VM起動後に作成されたスレッド数合計 |
getCurrentThreadCpuTime() | 18289000 | 現在のスレッドの合計 CPU 時間(ns) |
getCurrentThreadUserTime() | 16570000 | 現在のスレッドのユーザーモード実行CPU 時間(ns) |
個別のスレッドを指定することもできます。
メソッド | 説明 |
---|---|
getThreadAllocatedBytes(long id) | スレッドに割り当てられたヒープメモリー量 |
getThreadCpuTime(long ids) | スレッドの合計 CPU 時間(ns) |
getThreadUserTime(long ids) | スレッドの合計ユーザ CPU 時間(ns) |
getThreadInfo(long id) | 指定したスレッドIDのThreadInfo |
getAllThreadIds() | ライブスレッドのスレッドID配列 |
スレッドIDを指定して ThreadInfo からスタックトレースなど色々な情報を取ることができます。
for (long id : thread.getAllThreadIds()) { ThreadInfo info = thread.getThreadInfo(id); System.out.println(info); // "Timer-0" Id=10 RUNNABLE など
スレッドがらみはこの他にも色々と情報が取得できます。
ClassLoadingMXBean
クラスローダ関連です。
ClassLoadingMXBean classLoadingMx = ManagementFactory.getClassLoadingMXBean();
以下のような概要が取得できます。
メソッド | 出力例 | 説明 |
---|---|---|
getLoadedClassCount() | 669 | ロード済みクラス数 |
getUnloadedClassCount() | 1 | アンロードされたクラス数累計 |
getTotalLoadedClassCount() | 670 | ロードされたクラス数累計 |
isVerbose() | 詳細出力かどうか | |
setVerbose(boolean value) | 詳細出力の切り替え |
GarbageCollectorMXBean
GC 関連です。
Collection<GarbageCollectorMXBean> garbageCollectors = ManagementFactory.getGarbageCollectorMXBeans(); for (GarbageCollectorMXBean garbageCollector : garbageCollectors) { String gcName = garbageCollector.getName(); long gcCount = garbageCollector.getCollectionCount(); long gcTime = garbageCollector.getCollectionTime(); }
以下のような情報を得ることができます。
メソッド | 出力例 | 説明 |
---|---|---|
getName() | PS Scavenge | 名前 |
getCollectionCount() | 3 | GC数の合計 |
getCollectionTime() | 23453 | GC時間の累計(ms) |
com.sun.management.GarbageCollectorMXBean
にキャストすることでより詳細な情報を得ることができます。
com.sun.management.GarbageCollectorMXBean sunGcMx = (com.sun.management.GarbageCollectorMXBean)garbageCollector; GcInfo gcInfo = gc.getLastGcInfo();
サンプル
System.out に代表的な情報を出力するサンプルです。
import com.sun.management.OperatingSystemMXBean; import com.sun.management.ThreadMXBean; import com.sun.management.GarbageCollectorMXBean; import java.lang.management.*; import java.util.*; import java.util.logging.Logger; public class SystemMonitor { private static final Logger logger = Logger.getLogger(SystemMonitor.class.getName()); private final Timer timer; private final RuntimeMXBean runtimeMx; private final CompilationMXBean compilationMx; private final ThreadMXBean sunThreadMx; private final MemoryMXBean memoryMx; private final ClassLoadingMXBean classLoadingMx; private final OperatingSystemMXBean sunOsMx; private final Collection<GarbageCollectorMXBean> garbageCollectors; public SystemMonitor() { timer = new Timer(true); runtimeMx = ManagementFactory.getRuntimeMXBean(); compilationMx = ManagementFactory.getCompilationMXBean(); sunThreadMx = (com.sun.management.ThreadMXBean) ManagementFactory.getThreadMXBean(); memoryMx = ManagementFactory.getMemoryMXBean(); classLoadingMx = ManagementFactory.getClassLoadingMXBean(); sunOsMx = (com.sun.management.OperatingSystemMXBean) ManagementFactory.getOperatingSystemMXBean(); garbageCollectors = (List<GarbageCollectorMXBean>)(List<?>)ManagementFactory.getGarbageCollectorMXBeans(); } private final String[] systemInfoFmt = { ":: System Information", " Operating system : %s, Version : %s, Arch : %s", " Number of processors : %d, Physical memory : %s, Virtual memory : %s", ":: VM Information", " VM : %s, Version : %s, Vendor : %s, JIT compiler : %s", " Arguments : %s", " Classpath : %s", " boot : %s", " Lib Path : %s" }; public void systemInfo() { print(systemInfoFmt[0]); print(String.format(systemInfoFmt[1], sunOsMx.getName(), sunOsMx.getVersion(), sunOsMx.getArch() )); print(String.format(systemInfoFmt[2], sunOsMx.getAvailableProcessors(), prettyBytes(sunOsMx.getTotalPhysicalMemorySize()), prettyBytes(sunOsMx.getCommittedVirtualMemorySize()) )); print(systemInfoFmt[3]); print(String.format(systemInfoFmt[4], runtimeMx.getVmName(), runtimeMx.getVmVersion(), runtimeMx.getVmVendor(), (compilationMx != null) ? compilationMx.getName() : "-" )); print(String.format(systemInfoFmt[5], runtimeMx.getInputArguments().toString() )); print(String.format(systemInfoFmt[6], runtimeMx.getClassPath() )); print(String.format(systemInfoFmt[7], runtimeMx.isBootClassPathSupported() ? runtimeMx.getBootClassPath() : "-" )); print(String.format(systemInfoFmt[8], runtimeMx.getLibraryPath() )); } private final String[] tickFmt = { ":: System", " CPU usage : %.2f, Load average(last minute) : %.5f", " Physical memory : %s, Free : %s", " Swap space : %s, Free : %s", ":: VM Process", " Uptime : %s, Started : %s", " CPU usage : %.2f, CPU time : %s, JIT compile time : %s", ":: Heap", " Current : %s, Committed : %s, Init : %s, Max : %s", ":: Thread usage", " Live : %d, Peak : %d, Daemon : %d, TotalStarted : %d", ":: Class loading", " Current Loaded : %d, Loaded(total) : %d, Unloaded(total) : %d", ":: Garbage collector", " %s : Count : %d, Elapsed time : %s" }; public void tick() { print(""); print(tickFmt[0]); // System print(String.format(tickFmt[1], sunOsMx.getSystemCpuLoad(), sunOsMx.getSystemLoadAverage() )); print(String.format(tickFmt[2], prettyBytes(sunOsMx.getTotalPhysicalMemorySize()), prettyBytes(sunOsMx.getFreePhysicalMemorySize()) )); print(String.format(tickFmt[3], prettyBytes(sunOsMx.getTotalSwapSpaceSize()), prettyBytes(sunOsMx.getFreeSwapSpaceSize()) )); print(tickFmt[4]); // VM Process print(String.format(tickFmt[5], prettyDuration(runtimeMx.getUptime()), new Date(runtimeMx.getStartTime()).toString() )); print(String.format(tickFmt[6], sunOsMx.getProcessCpuLoad(), prettyDuration(sunOsMx.getProcessCpuTime() / 1000000), (compilationMx != null) ? prettyDuration(compilationMx.getTotalCompilationTime()) : "-" )); print(tickFmt[7]); // Heap MemoryUsage mu1 = memoryMx.getHeapMemoryUsage(); print(String.format(tickFmt[8], prettyBytes(mu1.getUsed()), prettyBytes(mu1.getCommitted()), prettyBytes(mu1.getInit()), prettyBytes(mu1.getMax()) )); print(tickFmt[9]); // Thread print(String.format(tickFmt[10], sunThreadMx.getThreadCount(), sunThreadMx.getPeakThreadCount(), sunThreadMx.getDaemonThreadCount(), sunThreadMx.getTotalStartedThreadCount() )); print(tickFmt[11]); // Class loading print(String.format(tickFmt[12], classLoadingMx.getLoadedClassCount(), classLoadingMx.getTotalLoadedClassCount(), classLoadingMx.getUnloadedClassCount() )); print(tickFmt[13]); // GarbageCollector for (GarbageCollectorMXBean gcMx : garbageCollectors) { print(String.format(tickFmt[14], gcMx.getName(), gcMx.getCollectionCount(), prettyDuration(gcMx.getCollectionTime()) )); } print(""); } public void start(long period) { systemInfo(); TimerTask timerTask = new TimerTask() { @Override public void run() { tick(); } }; timer.scheduleAtFixedRate(timerTask, 1 * 1000, period); } public void stop() { timer.cancel(); timer.purge(); } private void print(String msg) { System.out.println(msg); } public static String prettyBytes(long bytes) { return prettyBytes(bytes, true); } public static String prettyBytes(long bytes, boolean si) { int unit = si ? 1000 : 1024; if (bytes < unit) return bytes + " B"; int exp = (int) (Math.log(bytes) / Math.log(unit)); String pre = (si ? "kMGTPE" : "KMGTPE").charAt(exp - 1) + (si ? "" : "i"); return String.format("%.1f %sB", bytes / Math.pow(unit, exp), pre); } public static String prettyDuration(long millis) { long seconds = millis / 1000; long d = seconds / 86400; long h = (seconds % 86400) / 3600; long m = (seconds % 3600) / 60; long s = (seconds % 60); long ms = millis % 1000; return ((d > 0) ? d + "days" : "") + ((h > 0) ? h + "h" : "") + ((m > 0) ? m + "m" : "") + ((s > 0) ? s + "s" : "") + ((ms > 0) ? ms + "ms" : "0"); } }
以下のように使えます。
public static void main(String... args) throws Exception { SystemMonitor mx = new SystemMonitor(); mx.start(2000); // ... mx.stop(); }
Java1.6 時代のCPU使用率
OperatingSystemMXBean
の getProcessCpuLoad()
でCPU使用率が取れるようになりましたが、1.7 からなので、それ以前は以下の要領でCPU使用率を計算できます。
RuntimeMXBean runtimeMx = ManagementFactory.getRuntimeMXBean(); OperatingSystemMXBean osMx = (OperatingSystemMXBean) ManagementFactory.getOperatingSystemMXBean(); TimerTask task = new TimerTask() { final int nCPUs = osMx.getAvailableProcessors(); long prevUpTime = runtimeMx.getUptime(); long prevProcessCpuTime = osMx.getProcessCpuTime(); @Override public void run() { final long upTime = runtimeMx.getUptime(); final long processCpuTime = osMx.getProcessCpuTime(); final long elapsedCpu = processCpuTime - prevProcessCpuTime; final long elapsedTime = upTime - prevUpTime; float cpuUsage = elapsedCpu / (elapsedTime * 10000F * nCPUs); cpuUsage = Math.max(0F, Math.min(100F, cpuUsage)); System.out.println(String.format("%.1f", cpuUsage)); prevUpTime = upTime; prevProcessCpuTime = processCpuTime; } }; new Timer(true).scheduleAtFixedRate(task,5000, 5000);
ちなみに、getProcessCpuLoad()
は com.sun.management.OperatingSystemMXBean
ではなくて、java.lang.management.OperatingSystemMXBean
で公開しようぜ、という Issue が OpenJDKに挙がってます。