在localhost上运行JVM的列表

时间:2011-03-04 23:07:53

标签: java

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

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

8 个答案:

答案 0 :(得分:16)

您可以使用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<Integer, LocalVirtualMachine> virtualMachines = LocalVirtualMachine.getAllVirtualMachines();
    for (final Entry<Integer, LocalVirtualMachine> entry : virtualMachines.entrySet()) {
        System.out.println(entry.getKey() + " : " + entry.getValue().displayName());
    }
}

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

答案 1 :(得分: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

答案 2 :(得分:5)

您实际上可以使用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添加到bootstrap类路径中才能运行:

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

答案 3 :(得分:1)

我不了解Java 6,但我认为你可以通过从命令行运行jconsole来实现。

此外,如果您使用的是* nix平台,则可以发出如下命令:

ps aux | grep java
祝你好运!

答案 4 :(得分:1)

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

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


编辑:这是管理资料的documentation index。 特别有趣的是Monitoring and Management Using the JMX API点。

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

答案 5 :(得分:1)

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

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

以下是源代码的链接:

PerfDataFile.java

LocalVmManager

答案 6 :(得分: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的一些变体,默认情况下它在classpath上,有些你必须添加它。使用Maven依赖项执行此操作有点棘手,需要使用systemPath。

如果您想要更多信息,请点击列表,查看PaŭloEbermann的链接 - Monitoring and Management Using the JMX API

VirtualMachine vm = VirtualMachine.attach(pid);

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

vm.loadAgent(agentJarLibraryFullPath);

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

答案 7 :(得分:0)

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