在localhost上运行JVM的列表

如何在Java 6+中获取localhost上运行的JVM列表及其规范(即Java版本,运行线程等)?

Java API是否提供此类function? 是否有可以执行此操作的Java库?

您可以使用jps ,一个随jvm一起分发的命令行工具。 但是,我不知道它有任何普通的Java API。 但是,JConsole可以做你所要求的,所以我看看它的来源。 这是非常可怕的,但在环顾四周时,我发现了对jVisualVM类的引用,当你指定Java 6+时,可以看到它们。 这是我发现的:

这些类都在sun.tools ,所以首先你必须找到JVM附带的jconsole.jar (当然是假定Sun JVM)并将它添加到类路径中。 然后,可以获得活动VM的快速列表:

 public static void main(final String[] args) { final Map virtualMachines = LocalVirtualMachine.getAllVirtualMachines(); for (final Entry entry : virtualMachines.entrySet()) { System.out.println(entry.getKey() + " : " + entry.getValue().displayName()); } } 

一旦获得对JVM的引用,就可以使用Attach API与它们进行通信。

\jdk\bin目录中的jps打印一个正在运行的Java进程的列表,但不是它们的规范。 一些运行条件可用:

 C:\Java\jdk1.6.0_23\bin>jps -mlv 4660 -Dosgi.requiredJavaVersion=1.5 -Xms40m -Xmx512m -XX:MaxPermSize=256m 6996 sun.tools.jps.Jps -mlv -Dapplication.home=C:\Java\jdk1.6.0_23 -Xms8m 

实际上,您可以使用Attach API获取JVM列表,而无需使用jconsole.jar

下面演示了如何获取本地运行的JVM列表,获取一些属性,通过JMX连接到每个JVM,以及通过该连接获取更多信息。

 // ... import com.sun.tools.attach.*; import javax.management.*; // ... List descriptors = VirtualMachine.list(); for (VirtualMachineDescriptor descriptor : descriptors) { System.out.println("Found JVM: " + descriptor.displayName()); try { VirtualMachine vm = VirtualMachine.attach(descriptor); String version = vm.getSystemProperties().getProperty("java.runtime.version"); System.out.println(" Runtime Version: " + version); String connectorAddress = vm.getAgentProperties().getProperty("com.sun.management.jmxremote.localConnectorAddress"); if (connectorAddress == null) { vm.startLocalManagementAgent(); connectorAddress = vm.getAgentProperties().getProperty("com.sun.management.jmxremote.localConnectorAddress"); } JMXServiceURL url = new JMXServiceURL(connectorAddress); JMXConnector connector = JMXConnectorFactory.connect(url); MBeanServerConnection mbs = connector.getMBeanServerConnection(); ObjectName threadName = new ObjectName(ManagementFactory.THREAD_MXBEAN_NAME); Integer threadCount = (Integer)mbs.getAttribute(threadName, "ThreadCount"); System.out.println(" Thread count: " + threadCount); } catch (Exception e) { // ... } } 

此处列出了可用的MXBean 。 关于JMX的更多内容可以在这里找到,我从这个问题的另一个答案的评论中得到了。 上面的一些代码来自两个链接。

注意 :至少对我来说,我必须将tools.jar添加到bootstrap类路径中以便运行:

 $ java -Xbootclasspath/a:${JAVA_HOME}/lib/tools.jar -jar  

除了jps还有jstack工具,可以打印出任何java进程的堆栈跟踪。 其输出的开头包含VM版本,然后是带有堆栈跟踪的线程列表。

我认为所有三个jps,jstack和jconsole都是基于javax.management.*java.lang.management的Java Management Beans API实现的,所以请查看有关如何在自己的程序中执行此操作的更多信息。


编辑:这是管理内容的文档索引 。 特别有趣的是使用JMX API进行监控和管理 。

(是的,它不仅适用于自己的VM,也适用于同一系统上的其他VM,甚至适用于远程系统上的其他VM,如果它们公开了正确的接口。)

我今天发现,这基本上就是JPS的作用:只需列出文件夹/ tmp / hsperfdata_foo / ,其中foo是运行JVM的用户。

由于某些未知原因,有时候JVM被杀死时不会删除那里的文件。

以下是源代码的链接:

PerfDataFile.java

LocalVmManager

如果你只需要运行带有PID的JVM列表,这对我有用:

 package my.code.z025.util; import java.util.LinkedList; import java.util.List; import java.util.Set; import sun.jvmstat.monitor.HostIdentifier; import sun.jvmstat.monitor.MonitorException; import sun.jvmstat.monitor.MonitoredHost; import sun.jvmstat.monitor.MonitoredVm; import sun.jvmstat.monitor.MonitoredVmUtil; import sun.jvmstat.monitor.VmIdentifier; /** * Get list of all local active JVMs */ public class ActiveJavaVirtualMachineExplorer { /** * Represents successfully captured active java virtual machine */ public static class ActiveVm { private int pid; private String name; ... shortened ... } /** * Represents unsuccessfully captured active java virtual machine, a failure. * Keep cause exception. */ public static class FailedActiveVm extends ActiveVm { private Exception cause; ... shortened ... } /** * Get list of all local active JVMs. * 

* Returns something like: * ActiveVm [pid=7992, name=my.code.z025.util.launch.RunHttpServer] * ActiveVm [pid=6972, name=] * ActiveVm [pid=8188, name=my.code.z025.util.launch.RunCodeServer] * ActiveVm [pid=4532, name=org.eclipse.jdt.internal.junit.runner.RemoteTestRunner] * The pid=6972 must be Eclipse. So this approach is not water tight. */ public static List getActiveLocalVms() { List result = new LinkedList(); MonitoredHost monitoredHost; Set activeVmPids; try { monitoredHost = MonitoredHost.getMonitoredHost(new HostIdentifier((String) null)); activeVmPids = monitoredHost.activeVms(); for (Integer vmPid : activeVmPids) { try { MonitoredVm mvm = monitoredHost.getMonitoredVm(new VmIdentifier(vmPid.toString())); result.add(new ActiveVm(vmPid.intValue(), MonitoredVmUtil.mainClass(mvm, true))); mvm.detach(); } catch (Exception e) { result.add(new FailedActiveVm(vmPid.intValue(), e)); } } return result; } catch (java.net.URISyntaxException e) { throw new InternalError(e.getMessage()); } catch (MonitorException e) { throw new InternalError(e.getMessage()); } } }

应用程序不必与任何特殊的命令行参数一起运行,这样可以检测到。 无需激活JMX。

并非所有JVM应用程序都能很好地运行。 对于Eclipse,我只看到PID,但没有看到类名或命令行。

您必须将tool.jar添加到类路径中,它包含sun.jvmstat.*包。 tool.jar是JDK的一部分。 对于JDK / OS的一些变体,默认情况下它在classpath上,有些你必须添加它。 使用Maven依赖项执行此操作有点棘手,需要systemPath。

如果您想要更多信息,请点击列表,查看PaŭloEbermann的链接 – 使用JMX API进行监控和管理 。

 VirtualMachine vm = VirtualMachine.attach(pid); 

您从列表中获得的PID。 然后将您的代理插入(未经考虑的)Java(或任何JVM)应用程序。

 vm.loadAgent(agentJarLibraryFullPath); 

然后通过JMXConnector与您的代理进行通信。 您的代理可以为您收集所有统计信息。 我没有亲自尝试过。 您甚至可以通过这种方式检测(修改)运行时代码。 Profilers使用它。

我不知道Java 6,但我认为你可以通过从命令行运行jconsole来做到。

此外,如果您在* nix平台上,您可以发出如下命令:

 ps aux | grep java 

祝你好运!

据我所知,jps提供了使用它所属的jvm启动的进程列表。 如果您安装了多个JDK,我认为它不会有所帮助。 如果你想要一个所有java进程的列表,你必须使用“ps -ef | grep java”。 我见过很多次JVsualVM无法识别特定主机上运行的所有java进程。 如果您的要求特定于JVM启动的流程,则上述建议将适用。