JVM Management API

JVM本身提供了一組管理的API,通過該API,我們可以獲取得到JVM內部主要運行信息,包括內存各代的數據、JVM當前所有線程及其棧相關信息等等。各種JDK自帶的剖析工具,包括jps、jstack、jinfo、jstat、jmap、jconsole等,都是基於此API開發的。本篇對這部分內容進行一個詳細的說明。

參考:http://java.sun.com/javase/6/docs/api/java/lang/management/package-summary.html
一、Management API
我們先看一下從Sun JVM我們可以獲取到哪些信息,如下圖(來自於JConsole的MBean部分的截圖):

[Java性能剖析]JVM Management API


1.HotSpotDiagnostic:非標準的監控JMX,這塊是Sun JVM自帶的,主要提供了兩個功能

  • 修改JVM的啓動參數(譬如在不需要重啓的情況下設置-XX:+HeapDumpOnOutOfMemoryError參數使得JVM內存不足的時候自動dump出堆空間到文件提供後續分析)
  • Dump堆信息到文件,可以猜測jmap工具是基於此功能來完成的

我們通過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定義瞭解其提供的主要功能

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定義是

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性能剖析]JVM Management API


其中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我們可以通過下圖來了解其提供的主要信息

[Java性能剖析]JVM Management API
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);
}

二、編程獲取到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);

三、結束語
可以看到,通過標準的接口,我們已經可以獲得運行的JVM很詳細的信息,從運行JVM、操作系統,到內存、GC和線程,通過這些標準的接口我們已經可以對JVM進行功能完善的監控。但是僅此是不夠的,這部分接口描述的主要是JVM的總體性的信息,而無法提供更多的細節。在下一部分,我們將使用JPDA來更深入地瞭解JVM內部信息更細節的信息,並瞭解我們如何通過JVM TI實現自動的性能監控

發佈了0 篇原創文章 · 獲贊 1 · 訪問量 6820
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章