日韩性视频-久久久蜜桃-www中文字幕-在线中文字幕av-亚洲欧美一区二区三区四区-撸久久-香蕉视频一区-久久无码精品丰满人妻-国产高潮av-激情福利社-日韩av网址大全-国产精品久久999-日本五十路在线-性欧美在线-久久99精品波多结衣一区-男女午夜免费视频-黑人极品ⅴideos精品欧美棵-人人妻人人澡人人爽精品欧美一区-日韩一区在线看-欧美a级在线免费观看

歡迎訪問 生活随笔!

生活随笔

當前位置: 首頁 > 编程资源 > 编程问答 >内容正文

编程问答

JMX-JAVA进程监控利器

發布時間:2025/3/20 编程问答 24 豆豆
生活随笔 收集整理的這篇文章主要介紹了 JMX-JAVA进程监控利器 小編覺得挺不錯的,現在分享給大家,幫大家做個參考.

Java?管理擴展(Java Management Extension,JMX)是從jdk1.4開始的,但從1.5時才加到jdk里面,并把API放到java.lang.management包里面。

如果一個 Java 對象可以由一個遵循 JMX 規范的管理器應用管理,那么這個Java 對象就可以稱為一個可由 JMX 管理的資源。


要使一個 Java 對象可管理,則必須創建相應的 MBean 對象,并通過這些 MBean 對象管理相應的 Java 對象。當擁有 MBean 類后,需要將其實例化并注冊到 MBeanServer 上。


一共有四種類型的 MBean , 分別是標準類型 MBean, 動態類型 MBean, 開放類型 MBean 和模型類型 MBean。

?

注:

  • 一個java進程里面可以有多個不同名字的mBeanServer ,每個mbs都是一個獨立的容器,用了管理mbean
  • 每個mbs都可以注冊多個rmi port,http port等
  • platformMBeanServer 是由jvm創建的,并添加了一些系統的mbean,如cpu,內存,網絡,線程等等
  • ?

    1、本機使用

    當我們啟動java進程后,經常會使用jps,jinfo,jmap,jstat等jdk自帶的命令去查詢進程的狀態,這其中的原理就是,當java進程啟動后,會創建一個用于本機連接的“localConnectorAddress”放到當前用戶目錄下,當使用jps等連接時,會到當前用戶目錄下取到“localConnectorAddress”并連接。

    package com.dxz.study;import java.io.IOException; import java.util.List; import java.util.Map; import java.util.Properties; import java.util.Set;import javax.management.MBeanServerConnection; import javax.management.ObjectName; import javax.management.remote.JMXConnector; import javax.management.remote.JMXConnectorFactory; import javax.management.remote.JMXServiceURL;import org.junit.Test;import com.sun.tools.attach.VirtualMachine; import com.sun.tools.attach.VirtualMachineDescriptor;public class JmxTest {@Test public void test1() { List<VirtualMachineDescriptor> vms = VirtualMachine.list(); for (VirtualMachineDescriptor desc : vms) { VirtualMachine vm; try { System.out.println("desc:" + desc); System.out.println("進程id:"+desc.id()); vm = VirtualMachine.attach(desc); } catch (Exception e) { e.printStackTrace(); continue; } JMXConnector connector = null; try { Properties props = vm.getAgentProperties(); for (Map.Entry<Object, Object> entry : props.entrySet()) { System.out.println(entry.getKey() + "->" + entry.getValue()); } String connectorAddress = props.getProperty("com.sun.management.jmxremote.localConnectorAddress"); if (connectorAddress == null) { System.out.println("connectorAddress is null"); continue; } System.out.println("conn:" + connectorAddress); //以下代碼用于連接指定的jmx,本地或者遠程 JMXServiceURL url = new JMXServiceURL(connectorAddress); //JMXServiceURL url = new JMXServiceURL("service:jmx:rmi:///jndi/rmi://localhost:1099/TestJMXServer"); connector = JMXConnectorFactory.connect(url); MBeanServerConnection mbeanConn = connector.getMBeanServerConnection(); Set<ObjectName> beanSet = mbeanConn.queryNames(null, null); // ... } catch (Exception e) { e.printStackTrace(); } finally { try { if (connector != null) connector.close(); break; } catch (IOException e) { // TODO Auto-generated catch block e.printStackTrace(); } } } } }

    pom.xml

    <project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd"><modelVersion>4.0.0</modelVersion><groupId>com.dxz</groupId><artifactId>study</artifactId><version>0.0.1-SNAPSHOT</version><packaging>jar</packaging><name>study</name><url>http://maven.apache.org</url><properties><project.build.sourceEncoding>UTF-8</project.build.sourceEncoding></properties><dependencies><dependency><groupId>junit</groupId><artifactId>junit</artifactId><version>4.1</version><scope>test</scope></dependency><dependency><groupId>org.glassfish.external</groupId><artifactId>opendmk_jdmkrt_jar</artifactId><version>1.0-b01-ea</version></dependency><dependency><groupId>org.jmockit</groupId><artifactId>jmockit</artifactId><version>1.24</version></dependency></dependencies> </project>

    上面代碼有時候取不到本地連接地址,這個時候需要嘗試讓agent加載management-agent.jar,完整代碼如下:

    ?

    package com.dxz.study;import java.io.File; import java.io.IOException; import java.lang.reflect.Method; import java.net.URL; import java.net.URLClassLoader; import java.util.List; import java.util.Properties;public class AbstractJmxCommand {private static final String CONNECTOR_ADDRESS = "com.sun.management.jmxremote.localConnectorAddress";public static String getJVM() {return System.getProperty("java.vm.specification.vendor");}public static boolean isSunJVM() {// need to check for Oracle as that is the name for Java7 onwards.return getJVM().equals("Sun Microsystems Inc.") || getJVM().startsWith("Oracle");}public static void main(String[] args) {if (args == null || args.length == 0) {System.out.println("Usage: pid");return;}int pid = Integer.valueOf(args[0]);System.out.println(new AbstractJmxCommand().findJMXUrlByProcessId(pid));}/*** Finds the JMX Url for a VM by its process id* * @param pid* The process id value of the VM to search for.* * @return the JMX Url of the VM with the given pid or null if not found.*/// @SuppressWarnings({ "rawtypes", "unchecked" })protected String findJMXUrlByProcessId(int pid) {if (isSunJVM()) {try {// Classes are all dynamically loaded, since they are specific// to Sun VM// if it fails for any reason default jmx url will be used// tools.jar are not always included used by default class// loader, so we// will try to use custom loader that will try to load tools.jar String javaHome = System.getProperty("java.home");String tools = javaHome + File.separator + ".." + File.separator + "lib" + File.separator + "tools.jar";URLClassLoader loader = new URLClassLoader(new URL[] { new File(tools).toURI().toURL() });Class virtualMachine = Class.forName("com.sun.tools.attach.VirtualMachine", true, loader);Class virtualMachineDescriptor = Class.forName("com.sun.tools.attach.VirtualMachineDescriptor", true,loader);Method getVMList = virtualMachine.getMethod("list", (Class[]) null);Method attachToVM = virtualMachine.getMethod("attach", String.class);Method getAgentProperties = virtualMachine.getMethod("getAgentProperties", (Class[]) null);Method getVMId = virtualMachineDescriptor.getMethod("id", (Class[]) null);List allVMs = (List) getVMList.invoke(null, (Object[]) null);for (Object vmInstance : allVMs) {String id = (String) getVMId.invoke(vmInstance, (Object[]) null);if (id.equals(Integer.toString(pid))) {Object vm = attachToVM.invoke(null, id);Properties agentProperties = (Properties) getAgentProperties.invoke(vm, (Object[]) null);String connectorAddress = agentProperties.getProperty(CONNECTOR_ADDRESS);if (connectorAddress != null) {return connectorAddress;} else {break;}}}// 上面的嘗試都不成功,則嘗試讓agent加載management-agent.jarMethod getSystemProperties = virtualMachine.getMethod("getSystemProperties", (Class[]) null);Method loadAgent = virtualMachine.getMethod("loadAgent", String.class, String.class);Method detach = virtualMachine.getMethod("detach", (Class[]) null);for (Object vmInstance : allVMs) {String id = (String) getVMId.invoke(vmInstance, (Object[]) null);if (id.equals(Integer.toString(pid))) {Object vm = attachToVM.invoke(null, id);Properties systemProperties = (Properties) getSystemProperties.invoke(vm, (Object[]) null);String home = systemProperties.getProperty("java.home");// Normally in ${java.home}/jre/lib/management-agent.jar// but might// be in ${java.home}/lib in build environments. String agent = home + File.separator + "jre" + File.separator + "lib" + File.separator+ "management-agent.jar";File f = new File(agent);if (!f.exists()) {agent = home + File.separator + "lib" + File.separator + "management-agent.jar";f = new File(agent);if (!f.exists()) {throw new IOException("Management agent not found");}}agent = f.getCanonicalPath();loadAgent.invoke(vm, agent, "com.sun.management.jmxremote");Properties agentProperties = (Properties) getAgentProperties.invoke(vm, (Object[]) null);String connectorAddress = agentProperties.getProperty(CONNECTOR_ADDRESS);// detach 這個vmdetach.invoke(vm, (Object[]) null);if (connectorAddress != null) {return connectorAddress;} else {break;}}}} catch (Exception ignore) {ignore.printStackTrace();}}return null;} }

    ?

    ?

    2、遠程連接

    毫無疑問,若想遠程連接訪問,肯定需要mBeanServer注冊一個或多個端口,如rmi端口,http端口等。

    2.1 rmi端口注冊及訪問

    有兩種方法,一種直接在代碼里面指定rmi端口,并綁定,如下,此種方法需要使用客戶端連接代碼訪問,另一種代碼不用指定端口,之需把mbean注冊到platformMBeanServer 里面,并在啟動進程時加jmx參數指定,用這種方法可以通過jconsole,jvisualvm遠程訪問。

    2.1.1 直接在代碼里面綁定端口

    @Test public void testJmxRmiRegist() throws Exception { int rmiPort = 2222; String jmxServerName = "com.dxz.study.TestJmxRmiRegist"; // jdkfolder/bin/rmiregistry.exe 9999 Registry registry = LocateRegistry.createRegistry(rmiPort); MBeanServer mbs = MBeanServerFactory.createMBeanServer(jmxServerName); System.out.println(mbs); // mbs = MBeanServerFactory.createMBeanServer(); // 新建MBean ObjectName, 在MBeanServer里標識注冊的MBean ObjectName name = new ObjectName(jmxServerName + ":type=HelloWorld"); // HtmlAdaptorServer adapter = new HtmlAdaptorServer(); // 在MBeanServer里注冊MBean, 標識為ObjectName(com.tenpay.jmx:type=Echo) mbs.registerMBean(new HelloWorld(), name); JMXServiceURL url = new JMXServiceURL("service:jmx:rmi:///jndi/rmi://localhost:" + rmiPort + "/" + jmxServerName); System.out.println("JMXServiceURL: " + url.toString()); JMXConnectorServer jmxConnServer = JMXConnectorServerFactory.newJMXConnectorServer(url, null, mbs); jmxConnServer.start(); Thread.sleep(1000 * 60 * 10); } 上面程序是新建了個mbeanserver,并通過rmi綁定到2222端口上,等待客戶端連接。

    2.1.2 通過jmx參數啟動進程

    #JVMARGS="$JVMARGS -Dcom.sun.management.jmxremote.port=8888 -Dcom.sun.management.jmxremote.ssl=false -Dcom.sun.management.jmxremote.authenticate=false" 通過這種把進程的jmx監控綁定指定的端口,即可在遠端通過jconsole進行監控。

    2.2通過http訪問

  • @Test public void testJmxHtmlAdapter() throws Exception { String jmxServerName = "com.dxz.study.TestJmxRmiRegist"; // jdkfolder/bin/rmiregistry.exe 9999 MBeanServer mbs = MBeanServerFactory.createMBeanServer(jmxServerName); System.out.println(mbs); // mbs = MBeanServerFactory.createMBeanServer(); // 新建MBean ObjectName, 在MBeanServer里標識注冊的MBean ObjectName name = new ObjectName(jmxServerName + ":type=HelloWorld"); // HtmlAdaptorServer adapter = new HtmlAdaptorServer(); // 創建MBean // 在MBeanServer里注冊MBean, 標識為ObjectName(com.tenpay.jmx:type=Echo) mbs.registerMBean(new HelloWorld(), name); HtmlAdaptorServer adapter = new HtmlAdaptorServer(); ObjectName adapterName; adapterName = new ObjectName(jmxServerName + ":name=" + "htmladapter"); adapter.setPort(8082); adapter.start(); mbs.registerMBean(adapter, adapterName); Thread.sleep(1000 * 60 * 10); }
  • 以上代碼用到了HtmlAdaptorServer, <dependency><groupId>org.glassfish.external</groupId><artifactId>opendmk_jdmkrt_jar</artifactId><version>1.0-b01-ea</version></dependency> 然后用瀏覽器訪問即可

    3、客戶端連接

    package com.dxz.study;import java.util.Set;import javax.management.MBeanServerConnection; import javax.management.ObjectName; import javax.management.remote.JMXConnector; import javax.management.remote.JMXConnectorFactory; import javax.management.remote.JMXServiceURL;import org.junit.Test;public class JmxClientTest {@Test public void test1() { try { JMXServiceURL url = new JMXServiceURL("service:jmx:rmi:///jndi/rmi://localhost:2222/com.dxz.study.TestJmxRmiRegist"); JMXConnector connector = JMXConnectorFactory.connect(url); MBeanServerConnection mbeanConn = connector.getMBeanServerConnection(); Set<ObjectName> beanSet = mbeanConn.queryNames(null, null); System.out.println(beanSet); }catch (Exception e) { // TODO Auto-generated catch block e.printStackTrace(); } } }

    結果:

    [com.dxz.study.TestJmxRmiRegist:type=HelloWorld, JMImplementation:type=MBeanServerDelegate]

    4、jconsole連接(待驗證)

    5、java進程自帶的mbean

    當我們在用jconsole、jvisualvm進行監控java進程時,通常都能看到cpu、內存、線程、垃圾收集等使用情況,其實數據都是通過jmx從jvm提供的一些mbean里面取的。主要如下:
    • 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 都包含了該內存池的詳細信息,如是否可用、當前已使用內存 / 最大使用內存值、以及設置最大內存值等等。

    • OperatingSystemMXBean

      該類提供的是操作系統的簡單信息,如構架名稱、當前 CPU 數、最近系統負載等。

    • RuntimeMXBean

      運行時信息包括當前虛擬機的名稱、提供商、版本號,以及 classpath、bootclasspath 和系統參數等等。

    • ThreadMXBean

      在 Java 這個多線程的系統中,對線程的監控是相當重要的。ThreadMXBean 就是起到這個作用。ThreadMXBean 可以提供的信息包括各個線程的各種狀態,CPU 占用情況,以及整個系統中的線程狀況。從 ThreadMXBean 可以得到某一個線程的 ThreadInfo 對象。這個對象中則包含了這個線程的所有信息。

    要獲得這些信息,我們首先通過?java.lang.management.ManagementFactory這個工廠類來獲得一系列的 MXBean。 ClassLoadingMXBean mbs = ManagementFactory.getClassLoadingMXBean(); System.out.println("loadedClass:" + mbs.getLoadedClassCount());

    ?

    ?

    轉載于:https://www.cnblogs.com/duanxz/p/4474750.html

    總結

    以上是生活随笔為你收集整理的JMX-JAVA进程监控利器的全部內容,希望文章能夠幫你解決所遇到的問題。

    如果覺得生活随笔網站內容還不錯,歡迎將生活随笔推薦給好友。