2011-03-04 39 views
11

如何在Java 6+中获得本地主机上正在运行的JVM的列表及其规格(即Java版本,正在运行的线程等)?本地主机上正在运行的JVM的列表

Java API是否提供了这些功能?有没有可以做到这一点的Java库?

+1

的VisualVM可以做,所以必须有一个办法,虽然可能不是一件容易的一个。 – biziclop 2011-03-04 23:10:20

回答

14

您可以使用jps,与JVM分发的命令行工具。不过,我还没有意识到它有任何正常的Java API。不过,JConsole可以做你想问的,所以我看看它的来源。这非常可怕,但是在四处寻找时,我发现了对jVisualVM类的引用,在您指定Java 6+时可以看到。这里是我发现的:

这些类都在sun.tools,所以首先你必须找到你的JVM附带的jconsole.jar(当然假设是Sun JVM)并将它添加到你的类路径中。然后激活虚拟机的快速正肮脏的上市可以得到这样的:

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

一旦你得到了你的JVM的引用,你可以与他们使用Attach API通信。

+0

非常有趣!我也刚刚发现这个解决方案http://download.oracle.com/javase/6/docs/technotes/guides/management/agent.html#gdhkz。它使用JAVA_HOME/lib中的tools.jar(你必须将它添加到你的类路径中)。 – fsarradin 2011-03-05 15:22:26

8

jps\jdk\bin目录中打印正在运行的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 
1

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

另外,如果你是一个* nix的平台,你可以这样这样发出命令:

ps aux | grep java 

祝你好运!

+6

你是不是指'| grep java'? – 2011-03-04 23:22:56

1

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

我想的JPS,jstack和JConsole的所有三个是基于javax.management.*java.lang.management Java管理豆API实现的,所以在那里寻找如何做到这一点在自己的程序的详细信息。


编辑:这里是documentation index的管理的东西。 特别有趣似乎点Monitoring and Management Using the JMX API

(是的,它不仅适用于自己的虚拟机,也为其他的人在同一系统上,甚至对远程系统上的,如果他们暴露右侧接口)。

+0

我相信'java.lang.management'包含类,同时允许您检查当前正在运行的JVM,而不是与您在同一台计算机上的其他JVM。 – 2011-03-04 23:31:36

+0

我站好了!这是好东西。 – 2011-03-05 00:03:32

+0

谢谢你的链接:) – fsarradin 2011-03-05 15:25:46

0

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

1

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

由于某些未知原因,有时在JVM被终止时,那里的文件不会被删除。

这里是链接到源代码:

PerfDataFile.java

LocalVmManager

1

如果你只需要使用的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. 
    * <p> 
    * 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<ActiveVm> getActiveLocalVms() { 
     List<ActiveVm> result = new LinkedList<ActiveVm>(); 
     MonitoredHost monitoredHost; 
     Set<Integer> 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的一些变体,默认情况下它是在类路径上的,有些则需要添加它。这样做与Maven依赖关系有点棘手,systemPath是必需的。

如果您需要更多,然后只是列表,请检查PaŭloEbermann - Monitoring and Management Using the JMX API的链接。

VirtualMachine vm = VirtualMachine.attach(pid); 

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

vm.loadAgent(agentJarLibraryFullPath); 

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

4

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

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

// ... 

import com.sun.tools.attach.*; 
import javax.management.*; 

// ... 

    List<VirtualMachineDescriptor> 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的列表是here。有关JMX的更多信息,请参阅here,我从another answer的评论中获得了此问题。上面的代码来自两个链接。

注意:至少对我来说,我不得不添加tools.jar自举类路径它来运行:

$ java -Xbootclasspath/a:${JAVA_HOME}/lib/tools.jar -jar <jar> 
+0

LocalVirtualMachine在Java8中没有太多的可用,这个答案现在是正确的 – loicmathieu 2016-08-22 14:34:52

相关问题