检测虚拟机当前的状态总是 Java 开放人员所关心的,也正是因为如此,出现了大量的 profiler 工具来检测当前的虚拟机状态。从 Java SE 5 之后,在 JDK 中,我们有了一些 Java 的虚拟机检测 API,即 java.lang.management
包。 Management 包里面包括了许多 MXBean 的接口类和 LockInfo、MemoryUsage、MonitorInfo 和 ThreadInfo 等类。从名字可以看出,该包提供了虚拟机内存分配、垃圾收集(GC)情况、操作系统层、线程调度和共享锁,甚至编译情况的检测机制。这样一来,Java 的开发人员就可以很简单地为自己做一些轻量级的系统检测,来确定当前程序的各种状态,以便随时调整。
要获得这些信息,我们首先通过 java.lang.management.ManagementFactory
这个工厂类来获得一系列的 MXBean。包括:
- ClassLoadingMXBean
ClassLoadMXBean 包括一些类的装载信息,比如有多少类已经装载 / 卸载(unloaded),虚拟机类装载的 verbose 选项(即命令行中的 Java – verbose:class 选项)是否打开,还可以帮助用户打开 / 关闭该选项。
- CompilationMXBean
CompilationMXBean 帮助用户了解当前的编译器和编译情况,该 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 都包含了该内存池的详细信息,如是否可用、当前已使用内存 / 最大使用内存值、以及设置最大内存值等等。
- MemoryManagerMXBean
- OperatingSystemMXBean
该类提供的是操作系统的简单信息,如构架名称、当前 CPU 数、最近系统负载等。
- RuntimeMXBean
运行时信息包括当前虚拟机的名称、提供商、版本号,以及 classpath、bootclasspath 和系统参数等等。
- ThreadMXBean
在 Java 这个多线程的系统中,对线程的监控是相当重要的。ThreadMXBean 就是起到这个作用。ThreadMXBean 可以提供的信息包括各个线程的各种状态,CPU 占用情况,以及整个系统中的线程状况。从 ThreadMXBean 可以得到某一个线程的 ThreadInfo 对象。这个对象中则包含了这个线程的所有信息。
java.lang.management 和虚拟机的关系
我 们知道,management 和底层虚拟机的关系是非常紧密的。其实,有一些的是直接依靠虚拟机提供的公开 API 实现的,比如 JVMTI;而另外一些则不然,很大一块都是由虚拟机底层提供某些不公开的 API / Native Code 提供的。这样的设计方式,保证了 management 包可以提供足够的信息,并且使这些信息的提供又有足够的效率;也使 management 包和底层的联系非常紧密。
代码示例:
- import java.lang.management.MemoryUsage;
- import java.util.Date;
- import java.util.List;
- import java.util.Map;
- import org.apache.commons.lang.builder.ToStringBuilder;
- /**
- * @author lisen
- * @date 2013-11-22 上午09:23:30
- */
- public class SystemInfoBean {
- // 加载类的数量
- private int loadClazzCount;
- // 已经加载类的数量
- private long hasloadClazzCount;
- // 尚未加载类的数量
- private long hasUnloadClazzCount;
- // 堆内存信息
- private MemoryUsage heapMemoryUsage;
- // 非堆内存信息
- private MemoryUsage nonHeapMemoryUsage;
- // 操作系统的名称
- private String operateName;
- // 操作系统的进程数
- private int processListCount;
- // 操作系统的架构
- private String archName;
- // 操作系统的版本号码
- private String versionName;
- // 虚拟机的名称
- private String vmName;
- // 虚拟机的版本
- private String vmVersion;
- // 系统的供应商的名称
- private String vmVendor;
- // JVM启动时间
- private Date startTime;
- // 输入参数
- private List<String> arguments;
- // 系统参数
- private Map<String, String> systemProperties;
- //setter and getter...
- }
- import java.lang.management.ClassLoadingMXBean;
- import java.lang.management.ManagementFactory;
- import java.lang.management.MemoryMXBean;
- import java.lang.management.OperatingSystemMXBean;
- import java.lang.management.RuntimeMXBean;
- import java.util.Date;
- /**
- * @author lisen
- * @date 2013-11-22 上午09:27:03
- */
- public class SystemInfoUtils {
- private SystemInfoBean infoBean = null;
- private static class SingletonClassInstance {
- private static final SystemInfoUtils instance = new SystemInfoUtils();
- }
- public static SystemInfoUtils getInstance() {
- return SingletonClassInstance.instance;
- }
- private SystemInfoUtils() {
- infoBean = new SystemInfoBean();
- // 操作系统信息
- OperatingSystemMXBean operateSystemMBean = ManagementFactory
- .getOperatingSystemMXBean();
- String operateName = operateSystemMBean.getName();
- infoBean.setOperateName(operateName);
- int processListCount = operateSystemMBean.getAvailableProcessors();
- infoBean.setProcessListCount(processListCount);
- String archName = operateSystemMBean.getArch();// System.getProperty("os.arch");
- infoBean.setArchName(archName);
- String versionName = operateSystemMBean.getVersion();// System.getProperty("os.version");
- infoBean.setVersionName(versionName);
- // 运行时信息
- RuntimeMXBean runtimeMXBean = ManagementFactory.getRuntimeMXBean();
- String vmName = runtimeMXBean.getVmName();
- infoBean.setVmName(vmName);
- String vmVersion = runtimeMXBean.getVmVersion();
- // infoBean.setVmVersion(vmVersion);
- infoBean.setVmVersion(System.getProperty("java.version") + " ("
- + vmVersion + ")");
- String vmVendor = runtimeMXBean.getVmVendor();
- infoBean.setVmVendor(vmVendor);
- long startTime = runtimeMXBean.getStartTime();
- infoBean.setStartTime(new Date(startTime));
- infoBean.setArguments(runtimeMXBean.getInputArguments());
- infoBean.setSystemProperties(runtimeMXBean.getSystemProperties());
- }
- public SystemInfoBean getSystemInfo() {
- // 类信息
- ClassLoadingMXBean classLoadMXBean = ManagementFactory
- .getClassLoadingMXBean();
- int loadClazzCount = classLoadMXBean.getLoadedClassCount();
- infoBean.setLoadClazzCount(loadClazzCount);
- long hasloadClazzCount = classLoadMXBean.getTotalLoadedClassCount();
- infoBean.setHasloadClazzCount(hasloadClazzCount);
- long hasUnloadClazzCount = classLoadMXBean.getUnloadedClassCount();
- infoBean.setHasUnloadClazzCount(hasUnloadClazzCount);
- // 内存
- MemoryMXBean memoryUsage = ManagementFactory.getMemoryMXBean();
- infoBean.setHeapMemoryUsage(memoryUsage.getHeapMemoryUsage());
- infoBean.setNonHeapMemoryUsage(memoryUsage.getNonHeapMemoryUsage());
- return infoBean;
- }
- }