如何获取Java进程的ID?
我知道有几种与平台相关的黑客,但是我希望有一个更通用的解决方案。
如何获取Java进程的ID?
我知道有几种与平台相关的黑客,但是我希望有一个更通用的解决方案。
Answers:
不存在可以保证在所有jvm实现中都能工作的与平台无关的方式。
ManagementFactory.getRuntimeMXBean().getName()
看起来是最好的(最近的)解决方案。它很短,并且可能在广泛使用的每个实现中都起作用。
在linux + windows上,它返回一个类似12345@hostname
(12345
是进程ID)的值。但是请注意,根据docs,不能保证该值:
返回代表正在运行的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调用“系统”库。
error: cannot find symbol
jdk9
这是一种后门方法,该方法可能不适用于所有VM,但应同时在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);
getDeclaredMethod
对返回的对象执行jvm.get(runtime)
。
尝试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();
}
以下方法尝试从中提取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>")
例如,只需致电。
对于较早的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";
}
int pid = Integer.parseInt(new File("/proc/self").getCanonicalFile().getName());
。为什么要额外旋转呢?
getCanonicalFile()
将“自我”转换为PID 的方法中是否存在某种魔术?
您可以签出我的项目:GitHub上的JavaSysMon。它提供了进程ID和跨平台(目前为Windows,Mac OSX,Linux和Solaris)的其他功能(CPU使用率,内存使用率)
从Java 9开始,有一个Process.getPid()方法,该方法返回进程的本机ID:
public abstract class Process {
...
public long getPid();
}
要获取当前Java进程的进程ID,可以使用以下ProcessHandle
接口:
System.out.println(ProcessHandle.current().pid());
为了完整起见,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的注意事项。
我发现的最新消息是,至少在linux上有一个名为的系统属性sun.java.launcher.pid
。我的计划是使用它,如果找不到使用JMX bean
。
这取决于您从哪里寻找信息。
如果要从控制台中查找信息,则可以使用jps命令。该命令给出的输出类似于Unix ps命令,并且随JDK一起提供,因为我相信1.5
如果您从进程中查找,则RuntimeMXBean(如Wouter Coekaerts所说)可能是您的最佳选择。Windows上使用Sun JDK 1.6 u7的getName()的输出格式为[PROCESS_ID] @ [MACHINE_NAME]。但是,您可以尝试执行jps并从中解析结果:
String jps = [JDK HOME] + "\\bin\\jps.exe";
Process p = Runtime.getRuntime().exec(jps);
如果不带任何选项运行,则输出应为进程ID,后跟名称。
这是代码JConsole,并且可能是jps和VisualVM使用。它利用sun.jvmstat.monitor.*
package中的类
from 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回购中;用Maven配置它有点棘手tool.jar
可能包含与平台相关的(原生?)代码,因此它不容易分派更新:我刚刚仔细检查过JPS是否使用这种方式,即Jvmstat库(tool.jar的一部分)。因此,无需像外部示例一样将JPS称为外部进程,而直接调用Jvmstat库。您可以通过这种方式在本地运行的所有JVM列表。参见JPS 源代码:
基于Ashwin Jayaprakash 关于许可Apache 2.0 的答案(+1)SIGAR
,以下是我使用它仅获取当前进程的PID的方法:
import org.hyperic.sigar.Sigar;
Sigar sigar = new Sigar();
long pid = sigar.getPid();
sigar.close();
即使并非在所有平台上都可以使用,但在此处列出的Linux,Windows,OS X和各种Unix平台上也可以使用。
您可以getpid()
在JNR-Posix中尝试。
它具有Windows POSIX包装器,该包装器从libc调用getpid()。
我知道这是一个旧线程,但我想指出的是,用于获取PID的API(以及运行时对Java进程的其他操作)已添加到JDK 9中的Process类中:http:// openjdk。 java.net/jeps/102
我发现了一个可能有点过时的解决方案,并且没有在Windows 10以外的其他操作系统上尝试过,但我认为这是值得注意的。
如果您发现自己正在使用J2V8和nodejs,则可以运行一个简单的javascript函数,以返回Java进程的pid。
这是一个例子:
public static void main(String[] args) {
NodeJS nodeJS = NodeJS.createNodeJS();
int pid = nodeJS.getRuntime().executeIntegerScript("process.pid;\n");
System.out.println(pid);
nodeJS.release();
}
这是我的解决方案:
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;
}