java - 用于从运行中的 JVM 收集统计信息的 API

标签 java jvm

对于一个类项目,我想实现一个 Java 应用程序,它连接到本地 JVM 并收集堆使用情况、线程数、加载的类等统计信息。我在网上搜索了一个 API,第三方内置的,这将允许我这样做,但到目前为止我还没有成功。

有谁知道可以让我连接到正在运行的 JVM 并收集统计信息的 API?

最佳答案

以下类演示了如何连接到正在运行的 JVM 并建立 JMX 连接,并在必要时加载 JMX 代理。它将使用 MemoryMXBean 打印系统属性(这通过 JVM 连接工作,无需 JMX)和内存使用情况。使用其他 MXBean 类型很容易扩展以打印其他统计信息。

请注意,在 Java 9 之前,您必须手动将 JDK 的 tools.jar 添加到类路径中。在模块化软件中,您必须向 jdk.attach 模块添加依赖项。

import static java.lang.management.ManagementFactory.MEMORY_MXBEAN_NAME;
import static java.lang.management.ManagementFactory.newPlatformMXBeanProxy;

import java.io.*;
import java.lang.management.MemoryMXBean;
import java.lang.management.MemoryUsage;
import java.util.*;

import javax.management.MBeanServerConnection;
import javax.management.remote.JMXConnector;
import javax.management.remote.JMXConnectorFactory;
import javax.management.remote.JMXServiceURL;

import com.sun.tools.attach.*;

public class CmdLineTool
{
  static final String CONNECTOR_ADDRESS =
      "com.sun.management.jmxremote.localConnectorAddress";

  public static void main(String[] args)
  {
    if(args.length!=1)
      System.err.println("Usage: java CmdLineTool <pid>");
    else if(printStats(args[0])) return;
    System.out.println("Currently running");
    for(VirtualMachineDescriptor vmd:VirtualMachine.list())
      System.out.println(vmd.id()+"\t"+vmd.displayName());
  }

  private static boolean printStats(String id)
  {
    try
    {
      VirtualMachine vm=VirtualMachine.attach(id);
      System.out.println("Connected to "+vm.id());
      System.out.println("System Properties:");
      for(Map.Entry<?,?> en:vm.getSystemProperties().entrySet())
        System.out.println("\t"+en.getKey()+" = "+en.getValue());
      System.out.println();
      try
      {
        MBeanServerConnection sc=connect(vm);
        MemoryMXBean memoryMXBean =
          newPlatformMXBeanProxy(sc, MEMORY_MXBEAN_NAME, MemoryMXBean.class);
        getRamInfoHtml(memoryMXBean);
      } catch(IOException ex)
      {
        System.out.println("JMX: "+ex);
      }
      vm.detach();
      return true;
    } catch(AttachNotSupportedException | IOException ex)
    {
      ex.printStackTrace();
    }
    return false;
  }
  // requires Java 8, alternative below the code
  static MBeanServerConnection connect(VirtualMachine vm) throws IOException
  {
    String connectorAddress = vm.startLocalManagementAgent();
    JMXConnector c=JMXConnectorFactory.connect(new JMXServiceURL(connectorAddress));
    return c.getMBeanServerConnection();
  }

  static void getRamInfoHtml(MemoryMXBean memoryMXBean)
  {
    System.out.print("Heap:\t");
    MemoryUsage mu=memoryMXBean.getHeapMemoryUsage();
    System.out.println(
      "allocated "+mu.getCommitted()+", used "+mu.getUsed()+", max "+mu.getMax());
    System.out.print("Non-Heap:\t");
    mu=memoryMXBean.getNonHeapMemoryUsage();
    System.out.println(
      "allocated "+mu.getCommitted()+", used "+mu.getUsed()+", max "+mu.getMax());
    System.out.println(
      "Pending Finalizations: "+memoryMXBean.getObjectPendingFinalizationCount());
  }
}

上述解决方案的 connect 方法需要 Java 8。旧 Java 版本的替代方案如下所示

static MBeanServerConnection connect(VirtualMachine vm) throws IOException
{
  String connectorAddress = vm.getAgentProperties().getProperty(CONNECTOR_ADDRESS);
  if(connectorAddress == null)
  {
    System.out.println("loading agent");
    Properties props = vm.getSystemProperties();
    String home  = props.getProperty("java.home");
    String agent = home+File.separator+"lib"+File.separator+"management-agent.jar";
    try {
      vm.loadAgent(agent);
    } catch (AgentLoadException|AgentInitializationException ex) {
      throw new IOException(ex);
    }
    connectorAddress = vm.getAgentProperties().getProperty(CONNECTOR_ADDRESS);
    while(connectorAddress==null) try {
      Thread.sleep(1000);
      connectorAddress = vm.getAgentProperties().getProperty(CONNECTOR_ADDRESS);
    } catch(InterruptedException ex){}
  }
  JMXConnector c=JMXConnectorFactory.connect(new JMXServiceURL(connectorAddress));
  return c.getMBeanServerConnection();
}

关于java - 用于从运行中的 JVM 收集统计信息的 API,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/19394646/

相关文章:

java - 如何序列化复杂的 Map 对象?

java - java中的静态 block 和对象 block 访问

java - 哪个实时 (RTSJ) JVM 最受青睐?

达到 maxThreads 限制时 JBOSS 挂起

java - 传递 Intent 返回的 Uri 时 ContentResolver 中不支持的 Uri

java - 运行 map 缩减程序时出现错误 java.lang.RuntimeException : java. lang.ClassNotFoundException : wordcount_classes. WordCount$Map

java - 正在运行的 JVM 是否检测到计算机时区的更改?

JAVA - Class 类和 *.class 文件之间的区别?

java - 从 HttpURLConnection 获取 InputStream 对象时出现 FileNotFoundException

java - 为 hashmap 实现基于时间的队列