用于从正在运行的 JVM 收集统计信息的 API
对于一个类项目,我想实现一个 Java 应用程序,它连接到本地 JVM 并收集诸如堆使用情况、线程数、加载的类等统计信息.我在网上搜索了一个 API,第三方内置的,可以让我这样做,但到目前为止我还没有成功.
For a class project, I would like to implement a Java application that connects to a local JVM and gathers statistics such as heap usage, number of threads, loaded classes etc. I've searched online for an API, third party of built-in, that would allow me to do this but I have so far been unsuccessful.
有谁知道可以让我连接到正在运行的 JVM 并收集统计数据的 API?
Does anyone know of an API that will allow me to connect to a running JVM and gather statistics?
推荐答案
以下类演示了如何连接到正在运行的 JVM 并建立 JMX 连接,并在必要时加载 JMX 代理.它将打印系统属性(这通过 JVM 连接工作,无需 JMX)和使用 MemoryMXBean 的内存使用情况.使用其他 MXBean 类型可以轻松扩展以打印其他统计信息.
The following class demonstrates how to connect to a running JVM and establish a JMX connection, loading the JMX agent if necessary. It will print System Properties (this works through the JVM connection without the need for JMX) and the memory usage using the MemoryMXBean. It’s easy to extend to print other statistics using other MXBean types.
注意,在 Java 9 之前,您必须手动将 JDK 的 tools.jar
添加到类路径中.在模块化软件中,您必须向 jdk.attach
模块添加依赖项.
Note, that before Java 9, you have to add the tools.jar
of your JDK to the classpath manually. In modular software, you have to add a dependency to the jdk.attach
module.
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()+" "+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(" "+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: ");
MemoryUsage mu=memoryMXBean.getHeapMemoryUsage();
System.out.println(
"allocated "+mu.getCommitted()+", used "+mu.getUsed()+", max "+mu.getMax());
System.out.print("Non-Heap: ");
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 版本的替代方案看起来像
The connect
method of above solution requires Java 8. The alternative for older Java versions looks like
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();
}
相关文章