Как программа Java может получить свой собственный идентификатор процесса?
Как получить идентификатор моего Java-процесса?
Я знаю, что есть несколько зависящих от платформы хаков, но я бы предпочел более общее решение.
Ответы
Ответ 1
Существует не зависящий от платформы способ, который может быть гарантирован для работы во всех реализациях jvm.
ManagementFactory.getRuntimeMXBean().getName()
выглядит как лучшее (самое близкое) решение. Он короткий и, вероятно, работает в каждой реализации в широком использовании.
В linux + windows возвращается значение типа [email protected]
(12345
, являющееся идентификатором процесса). Остерегайтесь, что в соответствии с документами, никаких гарантий относительно этого значения нет:
Возвращает имя, представляющее запущенную виртуальную машину Java. Возвращаемая строка имени может быть любой произвольной строкой и виртуальной виртуальной машиной Java машинная реализация может выбрать встроенную платформу информацию в возвращаемой строке имени. Каждая работающая виртуальная машина может иметь другое имя.
В Java 9 можно использовать новый процесс API:
long pid = ProcessHandle.current().pid();
Ответ 2
Вы могли бы использовать JNA. К сожалению, пока нет общего JNA API для получения текущего идентификатора процесса, но каждая платформа довольно проста:
Windows
Убедитесь, что у вас есть jna-platform.jar
:
int pid = Kernel32.INSTANCE.GetCurrentProcessId();
Юникс
Объявляет:
private interface CLibrary extends Library {
CLibrary INSTANCE = (CLibrary) Native.loadLibrary("c", CLibrary.class);
int getpid ();
}
Затем:
int pid = CLibrary.INSTANCE.getpid();
Java 9
В Java 9 новый API процесса может использоваться для получения текущего идентификатора процесса. Сначала вы берете дескриптор текущего процесса, а затем запрашиваете PID:
long pid = ProcessHandle.current().pid();
Ответ 3
Вот бэкдор-метод, который может не работать со всеми виртуальными машинами, но должен работать как с linux, так и с окнами (оригинальный пример здесь):
java.lang.management.RuntimeMXBean runtime =
java.lang.management.ManagementFactory.getRuntimeMXBean();
java.lang.reflect.Field jvm = runtime.getClass().getDeclaredField("jvm");
jvm.setAccessible(true);
sun.management.VMManagement mgmt =
(sun.management.VMManagement) jvm.get(runtime);
java.lang.reflect.Method pid_method =
mgmt.getClass().getDeclaredMethod("getProcessId");
pid_method.setAccessible(true);
int pid = (Integer) pid_method.invoke(mgmt);
Ответ 4
Попробуйте Sigar. очень обширные API. Лицензия Apache 2.
private Sigar sigar;
public synchronized Sigar getSigar() {
if (sigar == null) {
sigar = new Sigar();
}
return sigar;
}
public synchronized void forceRelease() {
if (sigar != null) {
sigar.close();
sigar = null;
}
}
public long getPid() {
return getSigar().getPid();
}
Ответ 5
Следующий метод пытается извлечь PID из java.lang.management.ManagementFactory
:
private static String getProcessId(final String fallback) {
// Note: may fail in some JVM implementations
// therefore fallback has to be provided
// something like '<pid>@<hostname>', at least in SUN / Oracle JVMs
final String jvmName = ManagementFactory.getRuntimeMXBean().getName();
final int index = jvmName.indexOf('@');
if (index < 1) {
// part before '@' empty (index = 0) / '@' not found (index = -1)
return fallback;
}
try {
return Long.toString(Long.parseLong(jvmName.substring(0, index)));
} catch (NumberFormatException e) {
// ignore
}
return fallback;
}
Просто вызовите getProcessId("<PID>")
, например.
Ответ 6
Вы можете проверить мой проект: JavaSysMon на GitHub. Он предоставляет идентификатор процесса и кучу других вещей (использование процессора, использование памяти) кросс-платформенную (в настоящее время Windows, Mac OSX, Linux и Solaris)
Ответ 7
Для более старых JVM, в linux...
private static String getPid() throws IOException {
byte[] bo = new byte[256];
InputStream is = new FileInputStream("/proc/self/stat");
is.read(bo);
for (int i = 0; i < bo.length; i++) {
if ((bo[i] < '0') || (bo[i] > '9')) {
return new String(bo, 0, i);
}
}
return "-1";
}
Ответ 8
Так как Java 9 существует метод Process.getPid(), который возвращает собственный идентификатор процесса:
public abstract class Process {
...
public long getPid();
}
Чтобы получить идентификатор процесса текущего процесса Java, можно использовать интерфейс ProcessHandle
:
System.out.println(ProcessHandle.current().pid());
Ответ 9
Для полноты есть оболочка Spring Boot для
String jvmName = ManagementFactory.getRuntimeMXBean().getName();
return jvmName.split("@")[0];
решение. Если требуется целое число, то это можно суммировать с одним слоем:
int pid = Integer.parseInt(ManagementFactory.getRuntimeMXBean().getName().split("@")[0]);
Если кто-то использует Spring boot уже, он/он может использовать org.springframework.boot.ApplicationPid
ApplicationPid pid = new ApplicationPid();
pid.toString();
Метод toString() печатает pid или '???'.
Предостережения с использованием ManagementFactory уже обсуждаются в других ответах.
Ответ 10
public static long getPID() {
String processName = java.lang.management.ManagementFactory.getRuntimeMXBean().getName();
if (processName != null && processName.length() > 0) {
try {
return Long.parseLong(processName.split("@")[0]);
}
catch (Exception e) {
return 0;
}
}
return 0;
}
Ответ 11
Последнее, что я обнаружил, это системное свойство sun.java.launcher.pid
, доступное по крайней мере на linux. Мой план состоит в том, чтобы использовать это, и если он не найден, используйте JMX bean
.
Ответ 12
В Scala:
import sys.process._
val pid: Long = Seq("sh", "-c", "echo $PPID").!!.trim.toLong
Это должно дать вам обходное решение для Unix-систем, пока не будет выпущена Java 9.
(Я знаю, вопрос был о Java, но поскольку нет эквивалентного вопроса для Scala, я хотел оставить это для Scala пользователей, которые могли бы споткнуться в один и тот же вопрос.)
Ответ 13
Это зависит от того, откуда вы ищете информацию.
Если вы ищете информацию с консоли, вы можете использовать команду jps. Команда дает результат, подобный команде Unix ps, и поставляется с JDK, так как я полагаю, что 1.5
Если вы смотрите на процесс, RuntimeMXBean (как сказал Wouter Coekaerts), вероятно, ваш лучший выбор. Результат getName() для Windows с использованием Sun JDK 1.6 u7 находится в форме [PROCESS_ID] @[MACHINE_NAME]. Однако вы можете попытаться выполнить jps и проанализировать результат:
String jps = [JDK HOME] + "\\bin\\jps.exe";
Process p = Runtime.getRuntime().exec(jps);
Если запустить без параметров, то результатом должен быть идентификатор процесса, за которым следует имя.
Ответ 14
java.lang.management.ManagementFactory.getRuntimeMXBean().getName().split("@")[0]
Ответ 15
Это код JConsole, и, возможно, использует jps и VisualVM. В нем используются классы из
sun.jvmstat.monitor.*
, от tool.jar
.
package my.code.a003.process;
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;
public class GetOwnPid {
public static void main(String[] args) {
new GetOwnPid().run();
}
public void run() {
System.out.println(getPid(this.getClass()));
}
public Integer getPid(Class<?> mainClass) {
MonitoredHost monitoredHost;
Set<Integer> activeVmPids;
try {
monitoredHost = MonitoredHost.getMonitoredHost(new HostIdentifier((String) null));
activeVmPids = monitoredHost.activeVms();
MonitoredVm mvm = null;
for (Integer vmPid : activeVmPids) {
try {
mvm = monitoredHost.getMonitoredVm(new VmIdentifier(vmPid.toString()));
String mvmMainClass = MonitoredVmUtil.mainClass(mvm, true);
if (mainClass.getName().equals(mvmMainClass)) {
return vmPid;
}
} finally {
if (mvm != null) {
mvm.detach();
}
}
}
} catch (java.net.URISyntaxException e) {
throw new InternalError(e.getMessage());
} catch (MonitorException e) {
throw new InternalError(e.getMessage());
}
return null;
}
}
Есть несколько уловов:
-
tool.jar
- это библиотека, распространяемая с Oracle JDK, но не JRE!
- Вы не можете получить
tool.jar
из Maven repo; настроить его с помощью Maven немного сложно
-
tool.jar
, вероятно, содержит зависимый от платформы (native?) код, так что это нелегко
распространяемый
- Он работает в предположении, что все (локальные) запущенные JVM-приложения "контролируются". Это выглядит как
что из Java 6 все приложения обычно (если вы не настроите их на противоположную)
- Возможно, он работает только для Java 6 +
- Eclipse не публикует основной класс, поэтому вы не сможете легко получить Eclipse PID
Ошибка в MonitoredVmUtil?
UPDATE: я просто дважды проверил, что JPS использует этот путь, то есть библиотеку Jvmstat (часть tool.jar). Поэтому нет необходимости вызывать JPS в качестве внешнего процесса, вызывать библиотеку Jvmstat непосредственно, как показывает мой пример. Вы также можете получить список всех JVM runnin на localhost таким образом.
См. JPS исходный код:
Ответ 16
На основе Ashwin Jayaprakash answer (+1)
об лицензированном Apache 2.0 SIGAR
, вот как я использую его для получения только PID текущего процесса:
import org.hyperic.sigar.Sigar;
Sigar sigar = new Sigar();
long pid = sigar.getPid();
sigar.close();
Несмотря на то, что он не работает на всех платформах, он работает на Linux, Windows, OS X и различных платформах Unix, перечисленных здесь.
Ответ 17
Вы можете попробовать getpid()
в JNR-Posix.
У этого есть оболочка Windows POSIX, которая вызывает getpid() от libc.
Ответ 18
Я знаю, что это старый поток, но я хотел назвать, что API для получения PID (а также других манипуляций с процессом Java во время выполнения) добавляется в класс Process в JDK 9: http://openjdk.java.net/jeps/102
Ответ 19
Добавление к другим решениям.
с Java 10, чтобы получить process id
final RuntimeMXBean runtime = ManagementFactory.getRuntimeMXBean();
final long pid = runtime.getPid();
out.println("Process ID is '" + pid);
Ответ 20
Я нашел решение, которое может показаться немного странным, и я не пробовал его на других ОС, кроме Windows 10, но думаю, что стоит обратить на это внимание.
Если вы работаете с J2V8 и nodejs, вы можете запустить простую функцию javascript, возвращающую вам pid процесса java.
Вот пример:
public static void main(String[] args) {
NodeJS nodeJS = NodeJS.createNodeJS();
int pid = nodeJS.getRuntime().executeIntegerScript("process.pid;\n");
System.out.println(pid);
nodeJS.release();
}
Ответ 21
Вот мое решение:
public static boolean isPIDInUse(int pid) {
try {
String s = null;
int java_pid;
RuntimeMXBean rt = ManagementFactory.getRuntimeMXBean();
java_pid = Integer.parseInt(rt.getName().substring(0, rt.getName().indexOf("@")));
if (java_pid == pid) {
System.out.println("In Use\n");
return true;
}
} catch (Exception e) {
System.out.println("Exception: " + e.getMessage());
}
return false;
}
Ответ 22
Это то, что я использовал, когда у меня было подобное требование. Это правильно определяет PID процесса Java. Пусть ваш Java-код порождает сервер по предварительно определенному номеру порта, а затем выполняет команды ОС, чтобы узнать, что PID прослушивает порт. Для Linux
netstat -tupln | grep portNumber