2011-03-04 41 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

相關問題