JVM本 身提供了一组管理的API,经过该API,咱们能够获取获得JVM内部主要运行信息,包括内存各代的数据、JVM当前全部线程及其栈相关信息等等。各类 JDK自带的剖析工具,包括jps、jstack、jinfo、jstat、jmap、jconsole等,都是基于此API开发的。本篇对这部份内容进 行一个详细的说明。html
参考:http://java.sun.com/javase/6/docs/api/java/lang/management/package-summary.html
1、Management API
咱们先看一下从Sun JVM咱们能够获取到哪些信息,以下图(来自于JConsole的MBean部分的截图):
java
1.HotSpotDiagnostic:非标准的监控JMX,这块是Sun JVM自带的,主要提供了两个功能编程
修改JVM的启动参数(譬如在不须要重启的状况下设置-XX:+HeapDumpOnOutOfMemoryError参数使得JVM内存不足的时候自动dump出堆空间到文件提供后续分析)api
Dump堆信息到文件,能够猜想jmap工具是基于此功能来完成的jvm
咱们经过com.sun.management.HotSpotDiagnosticMXBean定义了解其主要功能工具
public interface HotSpotDiagnosticMXBean { void dumpHeap(String s, boolean flag) throws IOException; List getDiagnosticOptions(); VMOption getVMOption(String s); void setVMOption(String s, String s1); }
2.ClassLoading:加载的类的整体信息,咱们能够经过此MBean获取到JVM加载的类定义的整体信息,能够猜想JConsole的类功能就 是经过此MBean来提供的。咱们能够经过java.lang.management.ClassLoadingMXBean定义了解其提供的主要功能性能
public interface ClassLoadingMXBean { public long getTotalLoadedClassCount(); public int getLoadedClassCount(); public long getUnloadedClassCount(); public boolean isVerbose(); public void setVerbose(boolean value); }
3.Compilation:提供JVM的JIT(Just In Time)编译器(将bytecode编译成native code)的信息,咱们能够经过java.lang.management.CompilationMXBean定义了解其提供的主要功能url
public interface CompilationMXBean { public java.lang.String getName(); public boolean isCompilationTimeMonitoringSupported(); public long getTotalCompilationTime(); }
4.GarbageCollector:垃圾回收器信息,譬如在如上图中,咱们启动的JVM会包含一个Copy垃圾回收器(用于Young Gen垃圾回收)和一个MarkAndSweep垃圾回收器(用于Tenured Gen垃圾回收)。咱们能够经过java.lang.management.GarbageCollectorMXBean定义了解其提供的主要功能操作系统
public interface GarbageCollectorMXBean extends MemoryManagerMXBean { public long getCollectionCount(); public long getCollectionTime(); }
java.lang.management.MemoryManagerMXBean定义是.net
public interface MemoryManagerMXBean { public String getName(); public boolean isValid(); public String[] getMemoryPoolNames(); }
除了如上信息,Sun JVM在实现上还提供了一个额外的信息LastGCInfo,见com.sun.management.GarbageCollectorMXBean定义
public interface GarbageCollectorMXBean extends java.lang.management.GarbageCollectorMXBean { GcInfo getLastGcInfo(); }
咱们能够经过下面的截图了解GcInfo包含的主要信息
其中java.lang.management.MemoryUsage后续能够看说明
5.内存相关
能够猜想,JConsole的内存部分的功能都是经过此部分的相关Bean来完成的。
1)Memory/MemoryManager:内存块相关信息,经过这MBean咱们能够获取到内存的整体信息,并能够经过提供的gc操做进行强制gc 的功能(System.gc())。咱们能够经过java.lang.management.MemoryMXBean和 java.lang.management.MemoryManagerMXBean了解其主要提供的功能
public interface MemoryMXBean { public int getObjectPendingFinalizationCount(); public MemoryUsage getHeapMemoryUsage(); public MemoryUsage getNonHeapMemoryUsage(); public boolean isVerbose(); public void setVerbose(boolean value); public void gc(); }
其中java.lang.management.MemoryUsage咱们能够经过下图来了解其提供的主要信息
public interface MemoryManagerMXBean { public String getName(); public boolean isValid(); public String[] getMemoryPoolNames(); }
2)MemoryPool:经过该MBean能够了解JVM各内存块的信息,譬如对于Sun JVM,目前包括Eden Space、Suvivor Space、Tenured Gen、CodeCache、Perm Gen,能够猜想JConsole的内存监控功能就是经过此MBean来作到的。咱们能够经过 java.lang.management.MemoryPoolMXBean了解其主要提供的功能
public interface MemoryPoolMXBean { public String getName(); public MemoryType getType(); public MemoryUsage getUsage(); public MemoryUsage getPeakUsage(); public void resetPeakUsage(); public boolean isValid(); public String[] getMemoryManagerNames(); public long getUsageThreshold(); public void setUsageThreshold(long threshold); public boolean isUsageThresholdExceeded(); public long getUsageThresholdCount(); public boolean isUsageThresholdSupported(); public long getCollectionUsageThreshold(); public void setCollectionUsageThreshold(long threhsold); public boolean isCollectionUsageThresholdExceeded(); public long getCollectionUsageThresholdCount(); public MemoryUsage getCollectionUsage(); public boolean isCollectionUsageThresholdSupported(); }
6.系统运行信息
1)OperatingSystem:经过该MBean咱们能够了解到JVM所运行在的操做系统上的一些相关信息,经过java.lang.management.OperatingSystemMXBean定义咱们能够了解到其主要提供的功能
public interface OperatingSystemMXBean { public String getName(); public String getArch(); public String getVersion(); public int getAvailableProcessors(); public double getSystemLoadAverage(); }
SunJVM在此基础上提供更多的一些信息,能够经过com.sun.management.OperatingSystemMXBean了解一些额外能够获取到的信息
public interface OperatingSystemMXBean extends java.lang.management.OperatingSystemMXBean { long getCommittedVirtualMemorySize(); long getTotalSwapSpaceSize(); long getFreeSwapSpaceSize(); long getProcessCpuTime(); long getFreePhysicalMemorySize(); long getTotalPhysicalMemorySize(); }
2)Runtime:经过该MBean获取获取到JVM一些相关的信息,经过java.lang.management.RuntimeMXBean能够了解其主要提供的功能
public interface RuntimeMXBean { public String getName(); public String getVmName(); public String getVmVendor(); public String getVmVersion(); public String getSpecName(); public String getSpecVendor(); public String getSpecVersion(); public String getManagementSpecVersion(); public String getClassPath(); public String getLibraryPath(); public boolean isBootClassPathSupported(); public String getBootClassPath(); public java.util.List<String> getInputArguments(); public long getUptime(); public long getStartTime(); public java.util.Map<String, String> getSystemProperties(); }
能够经过RuntimeMXBean.getUptime()和OperatingSystemMXBean. getProcessCpuTime()来计算JVM占用的系统CPU比例的状况,JConsole的CPU视图就是经过这种方式计算的。
7.Threading:能够经过该MBean获取线程信息,包括线程状态、执行栈等。能够经过java.lang.management.ThreadMXBean了解其提供的主要功能
public interface ThreadMXBean { public int getThreadCount(); public int getPeakThreadCount(); public long getTotalStartedThreadCount(); public int getDaemonThreadCount(); public long[] getAllThreadIds(); public ThreadInfo getThreadInfo(long id); public ThreadInfo[] getThreadInfo(long[] ids); public ThreadInfo getThreadInfo(long id, int maxDepth); public ThreadInfo[] getThreadInfo(long[] ids, int maxDepth); public boolean isThreadContentionMonitoringSupported(); public boolean isThreadContentionMonitoringEnabled(); public void setThreadContentionMonitoringEnabled(boolean enable); public long getCurrentThreadCpuTime(); public long getCurrentThreadUserTime(); public long getThreadCpuTime(long id); public long getThreadUserTime(long id); public boolean isThreadCpuTimeSupported(); public boolean isCurrentThreadCpuTimeSupported(); public boolean isThreadCpuTimeEnabled(); public void setThreadCpuTimeEnabled(boolean enable); public long[] findMonitorDeadlockedThreads(); public void resetPeakThreadCount(); public long[] findDeadlockedThreads(); public boolean isObjectMonitorUsageSupported(); public boolean isSynchronizerUsageSupported(); public ThreadInfo[] getThreadInfo(long[] ids, boolean lockedMonitors, boolean lockedSynchronizers); public ThreadInfo[] dumpAllThreads(boolean lockedMonitors, boolean lockedSynchronizers); }
2、编程获取到JVM Manage信息
咱们能够经过JMX的方式读取到JVM Manage定义的MBean,以下是3种获取方法
1.监控应用与被监控应用位于同一JVM
MBeanServer server = ManagementFactory.getPlatformMBeanServer(); RuntimeMXBean rmxb = ManagementFactory.newPlatformMXBeanProxy(server, "java.lang:type=Runtime", RuntimeMXBean.class);
2.监控应用与被监控应用不位于同一JVM
1)首先在被监控的JVM的启动参数中加入以下的启动参数以启JVM代理
-Dcom.sun.management.jmxremote -Dcom.sun.management.jmxremote.port=127.0.0.1:8000 -Dcom.sun.management.jmxremote.authenticate=false -Dcom.sun.management.jmxremote.ssl=false
2)链接到代理上
JMXServiceURL url = new JMXServiceURL( "service:jmx:rmi:///jndi/rmi://127.0.0.1:8000/jmxrmi"); JMXConnector connector = JMXConnectorFactory.connect(url); RuntimeMXBean rmxb = ManagementFactory.newPlatformMXBeanProxy(connector .getMBeanServerConnection(),"java.lang:type=Runtime", RuntimeMXBean.class);
3.监控应用与被监控应用不位于同一JVM但在同一物理主机上(2的特化状况,经过进程Attach)
咱们使用JDK工具,如jmap、jstack等的时候,工具所在的JVM固然与被监控的JVM不是同一个,因此不能使用方式1,被监控的JVM通常也不 会在启动参数中增长JMX的支持,因此方式2也没有办法。还好Sun JVM给咱们提供了第3种非标准的方式,就是经过Attach到被监控的JVM进程,并在被监控的JVM中启动一个JMX代理,而后使用该代理经过2的方 式链接到被监控的JVM的JMX上。下面是一个使用范例,因为里面使用到的知识涉及到Java Instrutment(JVMTI的一个技术的Java实现)和Attach API,所以此处不作详细解析,在后续看完Java Instrutment和Attach API天然就会明白。(注意,仅在JDK6+中支持,另外,运行须要jdk的tools.jar包)
//Attach 到5656的JVM进程上,后续Attach API再讲解 VirtualMachine virtualmachine = VirtualMachine.attach("5656"); //让JVM加载jmx Agent,后续讲到Java Instrutment再讲解 String javaHome = virtualmachine.getSystemProperties().getProperty("java.home"); String jmxAgent = javaHome + File.separator + "lib" + File.separator + "management-agent.jar"; virtualmachine.loadAgent(jmxAgent, "com.sun.management.jmxremote"); //得到链接地址 Properties properties = virtualmachine.getAgentProperties(); String address = (String)properties.get("com.sun.management.jmxremote.localConnectorAddress"); //Detach virtualmachine.detach(); JMXServiceURL url = new JMXServiceURL(address); JMXConnector connector = JMXConnectorFactory.connect(url); RuntimeMXBean rmxb = ManagementFactory.newPlatformMXBeanProxy(connector .getMBeanServerConnection(), "java.lang:type=Runtime",RuntimeMXBean.class);
3、结束语 能够看到,经过标准的接口,咱们已经能够得到运行的JVM很详细的信息,从运行JVM、操做系统,到内存、GC和线程,经过这些标准的接口咱们已经能够对 JVM进行功能完善的监控。可是仅此是不够的,这部分接口描述的主要是JVM的整体性的信息,而没法提供更多的细节。在下一部分,咱们将使用JPDA来更 深刻地了解JVM内部信息更细节的信息,并了解咱们如何经过JVM TI实现自动的性能监控