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.jar
- Method 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 这个vm
- detach.invoke(vm, (Object[]) null);
- if (connectorAddress != null) {
- return connectorAddress;
- } else {
- break;
- }
- }
- }
- } catch (Exception ignore) {
- ignore.printStackTrace();
- }
- }
- return null;
- }
- }
2、远程连接
2.1 rmi端口注册及访问
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);
- }
2.1.2 通过jmx参数启动进程
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);
- }
- @Test
以上代码用到了HtmlAdaptorServer,
- <dependency>
- <groupId>org.glassfish.external</groupId>
- <artifactId>opendmk_jdmkrt_jar</artifactId>
- <version>1.0-b01-ea</version>
- </dependency>

3、客户端连接
5、java进程自带的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 都包含了该内存池的详细信息,如是否可用、当前已使用内存 / 最大使用内存值、以及设置最大内存值等等。
- MemoryManagerMXBean
- 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());
JMX-JAVA进程监控利器的更多相关文章
- 老技术新谈,Java应用监控利器JMX(2)
各位坐稳扶好,我们要开车了.不过在开车之前,我们还是例行回顾一下上期分享的要点. 上期由于架不住来自于程序员内心的灵魂的拷问,于是我们潜心修炼,与 Java 应用监控利器 JMX 正式打了个照面. J ...
- 轻量级监控平台之java进程监控脚本
轻量级监控平台之java进程监控脚本 #!/bin/bash #进程监控脚本 #功能需求: 上报机器Java进程的进程ID,对应的端口号service tcp端口号,tomcat http 端口号,以 ...
- Java进程监控
目录 1.引言 2. 程序启停, 为进程自定义项目名称 3. 操作系统判断 4. 获取进程信息 5. 内存,CPU信息 6. 堆内存信息 7. 端口信息 8. 线程信息 9. MXBean使用样例 9 ...
- 初识阿里开源的本地Java进程监控调试工具arthas(阿尔萨斯)
转载自:https://www.cnblogs.com/linhui0705/p/9795417.html 上个月,阿里开源了一个名为Arthas的监控工具.恰逢近期自己在写多线程处理业务,由此想到了 ...
- 老技术新谈,Java应用监控利器JMX(3)
各位坐稳扶好,我们要开车了.不过在开车之前,我们还是例行回顾一下上期分享的要点. 上期我们深入的聊了聊 JMX,把 JMX 的架构了解了七七八八,最后通过代码实战,解决系列疑问,实现远程动态修改应用参 ...
- 老技术新谈,Java应用监控利器JMX(1)
先聊聊最近比较流行的梗,来一次灵魂八问. 配钥匙师傅: 你配吗? 食堂阿姨: 你要饭吗? 算命先生: 你算什么东西? 快递小哥: 你是什么东西? 上海垃圾分拣阿姨: 你是什么垃圾? 滴滴司机: 你搞清 ...
- Java应用监控利器JMX
啥是 JMX? The Java Management Extensions (JMX) API is a standard API for management and monitoring of ...
- Linux记录-JMX监控JAVA进程
3.修改xxx.sh 加入export JAVA_OPTS="-Dcom.sun.management.jmxremote.authenticate=false -Dcom.sun.mana ...
- 利用VisualVm和JMX远程监控Java进程
自Java 6开始,Java程序启动时都会在JVM内部启动一个JMX agent,JMX agent会启动一个MBean server组件,把MBeans(Java平台标准的MBean + 你自己创建 ...
随机推荐
- SCRUM,一个采用迭代,增量方法来优化可预见控制风险
Scrum是一个用于开发和维持复杂产品的框架,是一个增量的,迭代的开发过程.在这个框架中,整个开发过程是由若干个短的迭代周期组成,一个短的迭代周期称为一个Sprint,每个Sprint的建议长度是2到 ...
- C++中怎么获取类的成员函数的函数指针?
用一个实际代码来说明. class A { public: staticvoid staticmember(){cout<<"static"<<endl;} ...
- hdu 4649 Professor Tian 反状态压缩+概率DP
思路:反状态压缩——把数据转换成20位的01来进行运算 因为只有20位,而且&,|,^都不会进位,那么一位一位地看,每一位不是0就是1,这样求出每一位是1的概率,再乘以该位的十进制数,累加,就 ...
- php关于private、public成员变量访问问题
如果类里面定义了__get($name)方法,则不论类的private成员还是public成员,都能够在类的外面通过类似$class->name访问到.如果是public变量,则不会自动调用ge ...
- cocos2d-x 常规库的图文件配置
LOCAL_PATH := $(call my-dir)include $(CLEAR_VARS) LOCAL_MODULE := cocos_lua_static LOCAL_MODULE_FILE ...
- 通过web代理进行跨域访问,http请求返回超时的问题定位
[现象] 在ajax通过web代理跨域访问时,http第一次登陆时正常,但是第二次再下发其他命令的时候总是返回 java.net.SocketTimeoutException: Read timed ...
- java:I/O 根据用户输入反馈信息
import java.io.*; class userInputIO{ //Java中成员变量有默认初始化,也就是如果不显式设置初始值的话就会被初始化为其类型的默认值(0.false.null等). ...
- C#字符串的常用操作
一.string关键字与StringBuilder类 C# 字符串是使用 string 关键字声明的一个字符数组.字符串是使用引号声明的,如下例所示: string s = "Hello, ...
- ArcGIS学习记录-Excel和Txt中XY点数据生成点Shape文件方法
(一)Excel中XY点数据生成点Shape文件方法 1.Excel表如下: 2.点击ArcGIS中的"+"号按钮,添加数据.选择第一步中制作好的Excel文件,点击Add按钮 ...
- RedMine项目管理系统安装问题(Windows版一键安装包)
安装准备: 操作环境:VMware10 下安装的windows10 系统 使用软件:<bitnami-redmine---windows-installer.exe> 问题描述: 安装过程 ...