Как получить в Java 6+ список запущенных JVM на локальном хосте и их спецификациях (т.е. версия Java, потоки и т.д.)?
Предоставляет ли Java API такие функции? Есть ли библиотека Java, которая может это сделать?
Как получить в Java 6+ список запущенных JVM на локальном хосте и их спецификациях (т.е. версия Java, потоки и т.д.)?
Предоставляет ли Java API такие функции? Есть ли библиотека Java, которая может это сделать?
Вы можете использовать jps
, инструмент командной строки, распространяемый вместе с jvm. Тем не менее, я не знаю ни одного нормального Java API. Однако JConsole может делать то, что вы просите, поэтому я посмотрел на его источник. Это было довольно страшно, но, оглядываясь по сторонам, я нашел ссылки на классы jVisualVM, которые видны, когда вы указываете Java 6+. Вот что я нашел:
Все классы находятся в sun.tools
, поэтому сначала вам нужно найти jconsole.jar
, который поставляется вместе с вашей JVM (подразумевает Sun JVM, конечно) и добавить его в свой путь к классам. Затем можно получить быстрый n-грязный список активных виртуальных машин:
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.
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
Фактически вы можете получить список 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
здесь здесь. Подробнее о JMX вообще можно найти здесь, который я получил из комментария другого ответа к этому вопросу. Некоторый код выше был получен из обеих ссылок.
Примечание. Для меня, по крайней мере, мне пришлось добавить tools.jar
в путь класса bootstrap для этого:
$ java -Xbootclasspath/a:${JAVA_HOME}/lib/tools.jar -jar <jar>
Я не знаю о Java 6, но я думаю, что вы можете сделать, запустив jconsole из командной строки.
Кроме того, если вы находитесь на платформе * nix, вы можете выпустить такую команду:
ps aux | grep java
Удачи!
Кроме jps
существует инструмент jstack
, который может распечатывать трассировку стека любого java-процесса. Начало его вывода содержит версию VM, а затем список потоков с трассировкой стека.
Я думаю, что все три jps, jstack и jconsole реализованы на основе API управления Java Beans в javax.management.*
и java.lang.management
, поэтому посмотрите там дополнительную информацию о том, как это сделать в вашей собственной программе.
Изменить: здесь индекс документации для материала управления. Особенно интересным представляется точка Мониторинг и управление с использованием JMX API.
(И да, он работает не только для собственной виртуальной машины, но и для других в одной и той же системе и даже для удаленных систем, если они выставляют правильный интерфейс.)
Это, я узнал сегодня, в основном, что делает JPS: просто перечислите папку /tmp/hsperfdata_foo/, где foo - это пользователь, запускающий JVM.
По какой-то неизвестной причине иногда файлы там не будут удалены при уничтожении JVM.
Вот ссылки на исходный код:
Если вам нужен только список запущенных 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 он по умолчанию находится в classpath, а некоторые вы должны его добавить. Выполнение этого с зависимостями Maven немного сложно, требуется системная плата.
Если вы хотите больше просто перечислить, проверьте ссылку от Paŭlo Ebermann - Мониторинг и управление с использованием JMX API.
VirtualMachine vm = VirtualMachine.attach(pid);
Где PID вы получаете из списка. Затем вставьте свой агент в (непредвиденное) приложение Java (или любое JVM).
vm.loadAgent(agentJarLibraryFullPath);
Затем свяжитесь с вашим агентом через JMXConnector. Ваш агент может собрать всю статистику для вас. Я лично этого не делал. Вы можете даже измерить (изменить) код времени выполнения таким образом. Профиляторы используют это.
Насколько я знаю, jps предоставляет список процессов, запущенных с использованием jvm, к которому он принадлежит. Если у вас установлено несколько JDK, я не думаю, что это поможет. Если вам нужен список всех java-процессов, вы должны использовать "ps -ef | grep java". Я неоднократно видел, что JVsualVM не смог идентифицировать все java-процессы, запущенные на конкретном хосте. Если ваше требование специфично для запущенных процессов JVM, то будут рассмотрены вышеприведенные предложения.