如何获取Java进程的id?
我知道有几种平台相关的hack方法,但我更倾向于一种更通用的解决方案。
没有一种平台无关的方式可以保证在所有jvm实现中都能正常工作。
ManagementFactory.getRuntimeMXBean().getName()
看起来是最好(最接近)的解决方案,通常包括PID。它很简短,并且 可能 在广泛使用的每个实现中都有效。
在linux + windows上,它返回类似于 "12345@hostname"
的值(其中12345
是进程ID)。但请注意,根据文档,对于这个值没有任何保证:
返回表示运行的Java虚拟机的名称。返回的名称字符串可以是任意字符串,Java虚拟机实现可以选择在返回的名称字符串中嵌入特定于平台的有用信息。每个正在运行的虚拟机可能具有不同的名称。
在Java 9中可以使用新的进程API:
long pid = ProcessHandle.current().pid();
你可以使用JNA。不幸的是,目前还没有通用的JNA API来获取当前进程ID,但每个平台都非常简单:
确保你有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中,可以使用新的进程API来获取当前进程的ID。首先获取当前进程的句柄,然后查询PID:
long pid = ProcessHandle.current().pid();
getpid()
解决方案同样适用于 OS X,只需通过 JNA 调用 "System" 库即可。 - Daniel Widdis这里有一个后门方法,可能不适用于所有虚拟机,但应该在Linux和Windows上都能使用(原始示例在此处):
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);
jvm.get(runtime)
返回的对象执行getDeclaredMethod
即可。 - Andrew T Finnell试试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();
}
java.lang.management.ManagementFactory
中提取PID: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>")
函数即可。
For older JVM, in 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";
}
int pid = Integer.parseInt(new File("/proc/self").getCanonicalFile().getName());
。为什么要多此一举呢? - David CitrongetCanonicalFile()
方法中的某种魔法将“self”转换为PID吗? - GreenGiant自Java 9以来,有一个Process.getPid()方法,它返回进程的本地ID:
public abstract class Process {
...
public long getPid();
}
要获取当前Java进程的进程ID,可以使用ProcessHandle
接口:
System.out.println(ProcessHandle.current().pid());
java.lang.management.ManagementFactory.getRuntimeMXBean().getName().split("@")[0]
在Scala中:
import sys.process._
val pid: Long = Seq("sh", "-c", "echo $PPID").!!.trim.toLong
这应该能在Unix系统上为您提供解决方法,直到Java 9发布。(我知道,问题是关于Java的,但由于Scala没有等效的问题,我想留下这个问题给可能遇到相同问题的Scala用户。)