JMX 和系统管理
??????????
检测虚拟机当前的状态总是 Java 开放人员所关心的,也正是因为如此,出现了大量的 profiler 工具来检测当前的虚拟机状态。从 Java SE 5 之后,在 JDK 中,我们有了一些 Java 的虚拟机检测 API,即 java.lang.management
包。Management 包里面包括了许多 MXBean 的接口类和 LockInfo、MemoryUsage、MonitorInfo 和 ThreadInfo 等类。从名字可以看出,该包提供了虚拟机内存分配、垃圾收集(GC)情况、操作系统层、线程调度和共享锁,甚至编译情况的检测机制。这样一来,Java 的开发人员就可以很简单地为自己做一些轻量级的系统检测,来确定当前程序的各种状态,以便随时调整。
要获得这些信息,我们首先通过 java.lang.management.ManagementFactory
这个工厂类来获得一系列的 MXBean。包括:
ClassLoadMXBean 包括一些类的装载信息,比如有多少类已经装载 / 卸载(unloaded),虚拟机类装载的 verbose 选项(即命令行中的 Java – verbose:class 选项)是否打开,还可以帮助用户打开 / 关闭该选项。
CompilationMXBeanCompilationMXBean 帮助用户了解当前的编译器和编译情况,该 mxbean 提供的信息不多。
GarbageCollectorMXBean相对于开放人员对 GC 的关注程度来说,该 mxbean 提供的信息十分有限,仅仅提供了 GC 的次数和 GC 花费总时间的近似值。但是这个包中还提供了三个的内存管理检测类:MemoryManagerMXBean,MemoryMXBean 和 MemoryPoolMXBean。
MemoryManagerMXBean这个类相对简单,提供了内存管理类和内存池(memory pool)的名字信息。
MemoryMXBean这个类提供了整个虚拟机中内存的使用情况,包括 Java 堆(heap)和非 Java 堆所占用的内存,提供当前等待 finalize 的对象数量,它甚至可以做 gc(实际上是调用 System.gc)。
MemoryPoolMXBean该信息提供了大量的信息。在 JVM 中,可能有几个内存池,因此有对应的内存池信息,因此,在工厂类中,getMemoryPoolMXBean() 得到是一个 MemoryPoolMXBean 的 list。每一个 MemoryPoolMXBean 都包含了该内存池的详细信息,如是否可用、当前已使用内存 / 最大使用内存值、以及设置最大内存值等等。
OperatingSystemMXBean该类提供的是操作系统的简单信息,如构架名称、当前 CPU 数、最近系统负载等。
RuntimeMXBean运行时信息包括当前虚拟机的名称、提供商、版本号,以及 classpath、bootclasspath 和系统参数等等。
ThreadMXBean在 Java 这个多线程的系统中,对线程的监控是相当重要的。ThreadMXBean 就是起到这个作用。ThreadMXBean 可以提供的信息包括各个线程的各种状态,CPU 占用情况,以及整个系统中的线程状况。从 ThreadMXBean 可以得到某一个线程的 ThreadInfo 对象。这个对象中则包含了这个线程的所有信息。
package com.easyway.space.commons.systems;import java.lang.management.ClassLoadingMXBean;import java.lang.management.CompilationMXBean;import java.lang.management.GarbageCollectorMXBean;import java.lang.management.LockInfo;import java.lang.management.ManagementFactory;import java.lang.management.MemoryMXBean;import java.lang.management.MemoryManagerMXBean;import java.lang.management.MemoryPoolMXBean;import java.lang.management.MemoryType;import java.lang.management.MemoryUsage;import java.lang.management.MonitorInfo;import java.lang.management.OperatingSystemMXBean;import java.lang.management.RuntimeMXBean;import java.lang.management.ThreadInfo;import java.lang.management.ThreadMXBean;import java.util.List;import java.util.Map;import java.util.Set;import java.util.Map.Entry;/** * 系统监控工具 * management 和底层虚拟机的关系是非常紧密的。其实,有一些的是直接依靠虚拟机提供的公 * 开 API 实现的,比如 JVMTI;而另外一些则不然,很大一块都是由虚拟机底层提供某些不公开 * 的 API / Native Code 提供的。这样的设计方式,保证了 management 包可以提供足够的信 * 息,并且使这些信息的提供又有足够的效率;也使 management 包和底层的联系非常紧密。 * @author longgangbai * */public class SystemUtils {/** *ClassLoadingMXBean ClassLoadMXBean 包括一些类的装载信息, * 比如有多少类已经装载 / 卸载(unloaded), * 虚拟机类装载的 verbose 选项(即命令行中的 Java – verbose:class 选项)是否打开, * 还可以帮助用户打开 / 关闭该选项。 */public static void getVMClassInformation(){ClassLoadingMXBean classLoadMXBean=ManagementFactory.getClassLoadingMXBean();int loadClazzCount=classLoadMXBean.getLoadedClassCount();System.out.println("加载类的数量:"+loadClazzCount);long hasloadClazzCount=classLoadMXBean.getTotalLoadedClassCount();System.out.println("已经加载类的数量:"+hasloadClazzCount);long hasUnloadClazzCount=classLoadMXBean.getUnloadedClassCount();System.out.println("尚未加载类的数量:"+hasUnloadClazzCount);boolean isVerbose=classLoadMXBean.isVerbose();System.out.println("是否开始加载类信息:"+isVerbose);//CompilationMXBean 帮助用户了解当前的编译器和编译情况,该 mxbean 提供的信息不多。CompilationMXBean compilationMXBean=ManagementFactory.getCompilationMXBean();String jitName=compilationMXBean.getName();System.out.println("即时编译的名称:"+jitName);long totalCompileTime=compilationMXBean.getTotalCompilationTime();System.out.println("总的编译时间:"+totalCompileTime+"/s");boolean isSupport=compilationMXBean.isCompilationTimeMonitoringSupported();if(isSupport){System.out.println("支持即时编译器编译监控");}else{System.out.println("不支持即时编译器编译监控");}List<GarbageCollectorMXBean> gcMXBeanList=ManagementFactory.getGarbageCollectorMXBeans();//相对于开放人员对 GC 的关注程度来说,该 mxbean 提供的信息十分有限,仅仅提供了 GC 的次数和 GC 花费总时间的近似值。for (GarbageCollectorMXBean gcMXBean : gcMXBeanList) {//内存池名称String[] poolNames=gcMXBean.getMemoryPoolNames();for (String poolName : poolNames) {System.out.println("poolNames="+poolName);}} //提供了内存管理类和内存池(memory pool)的名字信息。List<MemoryManagerMXBean> memoryMgrMXBeanList=ManagementFactory.getMemoryManagerMXBeans();//内存管理器的信息for (MemoryManagerMXBean memoryManagerMXBean : memoryMgrMXBeanList) {String[] poolNames=memoryManagerMXBean.getMemoryPoolNames();for (String poolName : poolNames) {System.out.println("poolNames="+poolName);}}//内存信息MemoryMXBean memoryMXBean=ManagementFactory.getMemoryMXBean();//java堆得使用情况信息MemoryUsage heapMemoryUsage=memoryMXBean.getHeapMemoryUsage();long usaged=heapMemoryUsage.getUsed();System.out.println("java 内存堆使用内存:"+usaged);long maxUsage=heapMemoryUsage.getMax();System.out.println("java 内存堆最大使用内存:"+maxUsage);long initUsage=heapMemoryUsage.getInit();System.out.println("java 内存堆初始化时占用内存:"+initUsage);List<MemoryPoolMXBean> memoryPoolMXBeanList=ManagementFactory.getMemoryPoolMXBeans();//该信息提供了大量的信息。在 JVM 中,可能有几个内存池,因此有对应的内存池信息,因此,在工厂类中//,getMemoryPoolMXBean() 得到是一个 MemoryPoolMXBean 的 list。每一个 MemoryPoolMXBean 都包含//了该内存池的详细信息,如是否可用、当前已使用内存 / 最大使用内存值、以及设置最大内存值等等。for (MemoryPoolMXBean memoryPoolMXBean : memoryPoolMXBeanList) {//内存池的名称String poolName=memoryPoolMXBean.getName();//内存管理器的名称String[] memoryMgrNames=memoryPoolMXBean.getMemoryManagerNames();for (String mgrName : memoryMgrNames) {System.out.println("内存管理器的名称:"+mgrName);} //java JVM最近内存的使用情况MemoryUsage memoryUsage=memoryPoolMXBean.getCollectionUsage();System.out.println("内存池的收集器内存使用率:"+memoryUsage.getUsed()/memoryUsage.getMax()+"%");memoryPoolMXBean.getCollectionUsageThreshold();memoryPoolMXBean.getCollectionUsageThresholdCount();MemoryType memoryType=memoryPoolMXBean.getType();System.out.println("内存的信息:"+memoryType.name());MemoryUsage memoryUage=memoryPoolMXBean.getUsage();System.out.println("内存池的内存使用率:"+memoryUage.getUsed()/memoryUage.getMax()+"%");memoryPoolMXBean.getUsageThreshold();System.out.println();memoryPoolMXBean.getUsageThresholdCount();System.out.println();}//该类提供的是操作系统的简单信息,如构架名称、当前 CPU 数、最近系统负载等。OperatingSystemMXBean operateSystemMBean=ManagementFactory.getOperatingSystemMXBean();String operateName=operateSystemMBean.getName();System.out.println("操作系统的名称:"+operateName);int processListCount=operateSystemMBean.getAvailableProcessors();System.out.println("操作系统的进程数:"+processListCount);String osArchName=operateSystemMBean.getArch();//System.getProperty("os.arch");System.out.println("操作系统的架构:"+osArchName);double loadAverage=operateSystemMBean.getSystemLoadAverage();System.out.println("操作系统的负载均衡信息:"+loadAverage);String versionName=operateSystemMBean.getVersion();//System.getProperty("os.version");System.out.println("操作系统的版本号码:"+versionName);//运行时信息包括当前虚拟机的名称、提供商、版本号,以及 classpath、bootclasspath 和系统参数等等。RuntimeMXBean runtimeMXBean=ManagementFactory.getRuntimeMXBean();String vmName=runtimeMXBean.getVmName();System.out.println("虚拟机的名称:"+vmName);String vmVersion=runtimeMXBean.getVmVersion();System.out.println("虚拟机的版本:"+vmVersion);Map<String, String> sysMaps=runtimeMXBean.getSystemProperties();Set<Entry<String,String>> keyLists=sysMaps.entrySet();for (Entry<String, String> entry : keyLists) {System.out.println(entry.getKey()+":"+entry.getValue());}String vmVendor=runtimeMXBean.getVmVendor();System.out.println("系统的供应商的名称:"+vmVendor);//类加载器的路径String clazzPath=runtimeMXBean.getClassPath();//System.getProperty("java.class.path")}System.out.println("操作系统的类加载器的名称:"+clazzPath);List<String> argsList=runtimeMXBean.getInputArguments();System.out.println("操作系统的参数信息");for (String args : argsList) {System.out.println(" "+args);}String libPath=runtimeMXBean.getLibraryPath();// System.getProperty("java.library.path")System.out.println("java 的类库路径:"+libPath );String specVersion=runtimeMXBean.getManagementSpecVersion();System.out.println("实施运行Java虚拟机管理接口规范 的版本"+specVersion);String specName=runtimeMXBean.getSpecName();System.out.println("规范的名称:"+specName);String specVender=runtimeMXBean.getSpecVendor();System.out.println("规范管理接口供应商 :"+specVender);long startTime=runtimeMXBean.getStartTime();System.out.println("java 虚拟机的开始启动的时间:"+startTime);runtimeMXBean.getSpecVersion();System.out.println("规范接口版本::"+operateName);String bottClassPath =runtimeMXBean.getBootClassPath();System.out.println("操作系统的bootstrap 的classloader:"+bottClassPath);//在 Java 这个多线程的系统中,对线程的监控是相当重要的。ThreadMXBean 就是起到这个作用。//ThreadMXBean 可以提供的信息包括各个线程的各种状态,CPU 占用情况,以及整个系统中的线//程状况。从 ThreadMXBean 可以得到某一个线程的 ThreadInfo 对象。这个对象中则包含了这个//线程的所有信息。//线程的信息ThreadMXBean threadMXBean=ManagementFactory.getThreadMXBean();//所有的线程的编号long[] threadIds=threadMXBean.getAllThreadIds();for (long threadId : threadIds) {//线程的信息ThreadInfo threadInfo=threadMXBean.getThreadInfo(threadId);//线程被阻塞的数量threadInfo.getBlockedCount();//被锁定线程的监控信息MonitorInfo[] monitorInfos=threadInfo.getLockedMonitors();for (MonitorInfo monitorInfo : monitorInfos) {int depth=monitorInfo.getLockedStackDepth();System.out.println("锁定的程度:"+depth);}//异步锁定的信息LockInfo[] lockinfos=threadInfo.getLockedSynchronizers();//锁定的信息for (LockInfo lockInfo : lockinfos) {System.out.println("锁定类的名称:"+lockInfo.getClassName());}//线程的名称String threadName=threadInfo.getThreadName();System.out.println("线程的名称:"+threadName);Thread.State state=threadInfo.getThreadState();System.out.println("线程的信息:"+state.name());}long cpuTime=threadMXBean.getCurrentThreadCpuTime();long curentTime=threadMXBean.getCurrentThreadUserTime();long threadCount=threadMXBean.getDaemonThreadCount();long peakliveThreadCount=threadMXBean.getPeakThreadCount();long threadCounts=threadMXBean.getThreadCount();System.out.println("当前处于live状态的线程总的数量:"+threadCounts);long totalThreadCount=threadMXBean.getTotalStartedThreadCount();System.out.println("JVM 启动之后,总的自动线程数量:"+totalThreadCount);}/** * * @return */public static final String getHeapMemoryUsage() {ClassLoadingMXBean mxbean;return ManagementFactory.getMemoryMXBean().getHeapMemoryUsage().getUsed()+ "/"+ ManagementFactory.getMemoryMXBean().getHeapMemoryUsage().getMax();} /** * 当前使用内存的百分比 * @return */public static final String getHeapMemoryUsagePercent() {return (((double) ManagementFactory.getMemoryMXBean().getHeapMemoryUsage().getUsed() / (double) ManagementFactory.getMemoryMXBean().getHeapMemoryUsage().getMax()) * 100L)+ "%";} /** * 当前非java堆占用的百分比 * @return */public static final String getNonHeapMemoryUsage() {return ManagementFactory.getMemoryMXBean().getNonHeapMemoryUsage().getUsed()+ "/"+ ManagementFactory.getMemoryMXBean().getNonHeapMemoryUsage().getMax();} /** * * @return */public static final String getNonHeapMemoryUsagePercent() {return (((double) ManagementFactory.getMemoryMXBean().getNonHeapMemoryUsage().getUsed() / (double) ManagementFactory.getMemoryMXBean().getNonHeapMemoryUsage().getMax()) * 100)+ "%";} /** * 获取线程数 * @return */public static final String getThreadCount() {return "" + ManagementFactory.getThreadMXBean().getThreadCount();}}
?