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實現自動的性能監控