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部分的截圖):
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);
- }
- 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);
- }
- 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();
- }
- 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();
- }
- 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();
- }
- 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();
- }
- 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();
- }
- 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();
- }
- 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();
- }
- 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();
- }
- 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();
- }
- 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();
- }
- 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);
- }
- 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);
- MBeanServer server = <span style="BACKGROUND-COLOR: #00ff40; COLOR: black; " id="casearchresult"><strong>ManagementFactory</strong></span>.getPlatformMBeanServer();
- RuntimeMXBean rmxb = <span style="BACKGROUND-COLOR: #00ff40; COLOR: black; " id="casearchresult"><strong>ManagementFactory</strong></span>.newPlatformMXBeanProxy(server,
- "java.lang:type=Runtime", RuntimeMXBean.class);
2.監控應用與被監控應用不位于同一JVM
1)首先在被監控的JVM的啟動參數中加入如下的啟動參數以啟JVM代理
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);
- JMXServiceURL url = new JMXServiceURL(
- "service:jmx:rmi:///jndi/rmi://127.0.0.1:8000/jmxrmi");
- JMXConnector connector = JMXConnectorFactory.connect(url);
- RuntimeMXBean rmxb = <span style="BACKGROUND-COLOR: #00ff40; COLOR: black; " id="casearchresult"><strong>ManagementFactory</strong></span>.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);
- //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 = <span style="BACKGROUND-COLOR: #00ff40; COLOR: black; " id="casearchresult"><strong>ManagementFactory</strong></span>.newPlatformMXBeanProxy(connector
- .getMBeanServerConnection(), "java.lang:type=Runtime",RuntimeMXBean.class);
三、結束語
可以看到,通過標準的接口,我們已經可以獲得運行的JVM很詳細的信息,從運行JVM、操作系統,到內存、GC和線程,通過這些標準的接口我們已經可以對
JVM進行功能完善的監控。但是僅此是不夠的,這部分接口描述的主要是JVM的總體性的信息,而無法提供更多的細節。在下一部分,我們將使用JPDA來更
深入地了解JVM內部信息更細節的信息,并了解我們如何通過JVM TI實現自動的性能監控
軟件包 java.lang.management 提供管理接口,用于監視和管理 Java 虛擬機以及 Java 虛擬機在其上運行的操作系統。
它同時允許從本地和遠程對正在運行的 Java 虛擬機進行監視和管理。
管理接口
ClassLoadingMXBean Java 虛擬機的類加載系統。
CompilationMXBean Java 虛擬機的編譯系統。
MemoryMXBean Java 虛擬機的內存系統。
ThreadMXBean Java 虛擬機的線程系統。
RuntimeMXBean Java 虛擬機的運行時系統。
OperatingSystemMXBean Java 虛擬機在其上運行的操作系統。
GarbageCollectorMXBean Java 虛擬機中的垃圾回收器。
MemoryManagerMXBean Java 虛擬機中的內存管理器。
MemoryPoolMXBean Java 虛擬機中的內存池。
示例如下:
import java.lang.management.ClassLoadingMXBean;
import java.lang.management.CompilationMXBean;
import java.lang.management.ManagementFactory;
import java.lang.management.MemoryMXBean;
import java.lang.management.ThreadMXBean;
import java.lang.management.RuntimeMXBean;
import java.lang.management.OperatingSystemMXBean;
import java.lang.management.MemoryPoolMXBean;
import java.util.List;
public class JVM {
public static void main(String[] args) {
//Java 虛擬機線程系統的管理接口 ThreadMXBean
ThreadMXBean th=(ThreadMXBean)ManagementFactory.getThreadMXBean() ;
System.out.println("活動線程的當前數目"+th.getThreadCount());
System.out.println("返回活動守護線程的當前數目"+th.getDaemonThreadCount());
System.out.println("Java 虛擬機啟動或峰值重置以來峰值活動線程計數"+th.getPeakThreadCount());
System.out.println("返回當前線程的總 CPU 時間"+th.getCurrentThreadUserTime());
System.out.println("當前線程在用戶模式中執行的 CPU 時間"+th.getCurrentThreadUserTime());
//Java 虛擬機的運行時系統的管理接口。 RuntimeMXBean
RuntimeMXBean run=(RuntimeMXBean)ManagementFactory.getRuntimeMXBean();
System.out.println("正在運行的 Java 虛擬機的名稱"+run.getName());
System.out.println("Java 虛擬機規范名稱"+run.getSpecName());
System.out.println("返回 Java 庫路徑"+run.getLibraryPath());
System.out.println("系統類加載器用于搜索類文件的 Java 類路徑"+run.getClassPath());
//用于操作系統的管理接口,Java 虛擬機在此操作系統上運行 OperatingSystemMXBean
OperatingSystemMXBean op=(OperatingSystemMXBean)ManagementFactory.getOperatingSystemMXBean();
System.out.println("返回操作系統的架構"+op.getArch());
System.out.println("返回操作系統名稱"+op.getName());
System.out.println("返回操作系統的版本"+op.getVersion());
System.out.println("Java 虛擬機可以使用的處理器數目"+op.getAvailableProcessors());
//內存池的管理接口。內存池表示由 Java 虛擬機管理的內存資源,
//由一個或多個內存管理器對內存池進行管理 MemoryPoolMXBean
List<MemoryPoolMXBean> list=ManagementFactory.getMemoryPoolMXBeans();
for(MemoryPoolMXBean mem:list){
System.out.println("Java 虛擬機啟動以來或自峰值重置以來此內存池的峰值內存使用量"+mem.getPeakUsage());
System.out.println("返回此內存池的類型"+mem.getType());
System.out.println("內存使用量超過其閾值的次數"+ mem.getUsage());
}
//Java 虛擬機內存系統的管理接口。 MemoryMXBean
MemoryMXBean mem=(MemoryMXBean)ManagementFactory.getMemoryMXBean();
System.out.println(" 返回用于對象分配的堆的當前內存使用量"+mem.getHeapMemoryUsage());
System.out.println("Java 虛擬機使用的非堆內存的當前內存使用量"+mem.getNonHeapMemoryUsage());
// Java 虛擬機的編譯系統的管理接口 CompilationMXBean
CompilationMXBean com=(CompilationMXBean)ManagementFactory.getCompilationMXBean();
System.out.println("即時 (JIT) 編譯器的名稱"+com.getName());
System.out.println("在編譯上花費的累積耗費時間的近似值(毫秒)"+com.getTotalCompilationTime());
//Java 虛擬機的類加載系統的管理接口 ClassLoadingMXBean
ClassLoadingMXBean cl=(ClassLoadingMXBean)ManagementFactory.getClassLoadingMXBean();
System.out.println("當前加載到 Java 虛擬機中的類的數量"+cl.getLoadedClassCount());
System.out.println("Java 虛擬機開始執行到目前已經加載的類的總數"+cl.getTotalLoadedClassCount());
System.out.println("Java 虛擬機開始執行到目前已經卸載的類的總數"+cl.getUnloadedClassCount());
}
}
- public class TestExcho {
- /**
- * @param args
- */
- public static void main(String[] args) throws Exception{
- MBeanServer server = ManagementFactory.getPlatformMBeanServer();
- ObjectName name = new ObjectName("com.demo.mbean:type=Excho");
- Echo ei =new Echo();
- server.registerMBean(ei,name);
- server.invoke(name, "setName", new Object[] { "jack"}, new String[] {"java.lang.String"});
- server.invoke(name, "showName", null, null);
- String yourName = (String)server.invoke(name, "fetchName", new Object[] { "mimi",10}, new String[] {"java.lang.String","int"});
- System.out.println("~~~"+yourName);
- CompositeData d = (CompositeData) server.invoke(name, "fetchConfig", null, null);
- String fn = (String)d.get("firstName");
- String ln = (String)d.get("lastName");
- System.out.println("~@@@~~"+fn+"@@"+ln);
- int num = (Integer)server.getAttribute(name, "Num");
- System.out.println("~OOOOO~~"+num);
- Thread.currentThread().sleep(Integer.MAX_VALUE);
- }
- }
文章列表