Список запущенных JVM на локальном хосте - PullRequest
11 голосов
/ 05 марта 2011

Как получить в Java 6+ список запущенных JVM на локальном хосте и их спецификации (например, версию Java, запущенные потоки и т. Д.)?

Предоставляет ли API Java такие функции?Есть ли библиотека Java, которая может сделать это?

Ответы [ 8 ]

16 голосов
/ 05 марта 2011

Вы можете использовать jps, инструмент командной строки, распространяемый вместе с jvm. Я не знаю ни одного нормального Java API для этого. Тем не менее, JConsole может делать то, что вы просите, поэтому я взглянул на его источник. Это было довольно страшно, но, оглядываясь по сторонам, я обнаружил ссылки на классы jVisualVM, которые хорошо видны, если указать Java 6+. Вот что я нашел:

Все классы находятся в sun.tools, поэтому сначала вы должны найти jconsole.jar, поставляемый с вашей JVM (предполагается, что 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 .

8 голосов
/ 05 марта 2011

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
5 голосов
/ 30 января 2016

На самом деле вы можете получить список JVM с помощью Attach API , не прибегая к использованию jconsole.jar.

Ниже показано, как получить список JVM, работающих локально, получить некоторые свойства, подключиться к каждому через JMX и получить дополнительную информацию по этому соединению.

// ...

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 s здесь . Больше о JMX в целом можно найти здесь , которое я получил из комментария к другого ответа на этот вопрос. Некоторый код выше взят из обеих ссылок.

Примечание : по крайней мере для меня мне пришлось добавить tools.jar в путь к начальной загрузке, чтобы запустить:

$ java -Xbootclasspath/a:${JAVA_HOME}/lib/tools.jar -jar <jar>
1 голос
/ 11 июня 2013

Если вам нужен просто список запущенных JVM с PID, это работает для меня:

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ŭlo Ebermann - Мониторинг и управление с использованием JMX API .

VirtualMachine vm = VirtualMachine.attach(pid);

Где PID вы получаете из списка.Затем вставьте свой агент в (непредвиденное) приложение Java (или любую JVM).

vm.loadAgent(agentJarLibraryFullPath);

Затем свяжитесь с вашим агентом через JMXConnector.Ваш агент может собрать всю статистику для вас.Я лично не пробовал это.Таким способом вы даже можете изменить (изменить) код времени выполнения.Профилировщики используют это.

1 голос
/ 19 октября 2011

Это, как я выяснил сегодня, в основном то, что делает JPS: просто перечислите папку / tmp / hsperfdata_foo / , где foo - пользователь, запускающий JVM.

По неизвестной причинеиногда файлы там не будут удаляться при уничтожении JVM.

Вот ссылки на исходный код:

PerfDataFile.java

LocalVmManager

1 голос
/ 05 марта 2011

В дополнение к jps есть инструмент jstack, который может распечатать трассировку стека любого Java-процесса. Начало его вывода содержит версию виртуальной машины, затем идет список потоков с трассировкой их стека.

Я думаю, что все три из jps, jstack и jconsole реализованы на основе API-интерфейсов Java Management Beans в javax.management.* и java.lang.management, поэтому поищите дополнительную информацию о том, как это сделать в вашей собственной программе.


Редактировать: вот индекс документации для руководства. Особенно интересным представляется пункт Мониторинг и управление с помощью JMX API .

(И да, он работает не только для собственной виртуальной машины, но и для других в той же системе, и даже для удаленных систем, если они предоставляют правильный интерфейс.)

1 голос
/ 05 марта 2011

Я не знаю о Java 6, но я думаю, что вы можете сделать это, запустив jconsole из командной строки.

Кроме того, если вы работаете на платформе * nix, вы можете выполнить такую ​​команду:

ps aux | grep java

Удачи!

0 голосов
/ 05 марта 2011

Насколько я знаю, jps предоставляет список процессов, запущенных с использованием jvm, которому он принадлежит. Если у вас установлено несколько JDK, я не думаю, что это поможет. Если вы хотите получить список всех процессов Java, вы должны использовать «ps -ef | grep java». Я видел много раз, когда JVsualVM не мог идентифицировать все процессы Java, работающие на определенном хосте. Если ваше требование относится к процессам, запущенным JVM, применимы приведенные выше предложения.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...