Java标准库里常见的公有API确实是没有获取当前进程的ID的方法,有时候挺郁闷的,就是需要自己的PID。
于是有各种workaround,其中有很靠谱的通过JNI调用外部的C/C++扩展,然后调用操作系统提供的相应API去获取PID;也有些不怎么靠谱的hack。这里要介绍的就是后者之一,只在Sun JDK或兼容的JDK上有效的方法。
代码例子如下:
import java.lang.management.ManagementFactory; import java.lang.management.RuntimeMXBean; public class ShowOwnPID { public static void main(String[] args) throws Exception { int pid = getPid(); System.out.println("pid: " + pid); System.in.read(); // block the program so that we can do some probing on it } private static int getPid() { RuntimeMXBean runtime = ManagementFactory.getRuntimeMXBean(); String name = runtime.getName(); // format: "pid@hostname" try { return Integer.parseInt(name.substring(0, name.indexOf('@'))); } catch (Exception e) { return -1; } } }
使用Sun JDK里RuntimeMXBean.getName()方法的实现,可以很轻松的拿到自身的PID。
运行这个程序可以看到类似以下的输出:
D:\experiment>java ShowOwnPID pid: 11704
这个时候再跑一个jps来看看当前都有哪些Java进程的话,可以看到:
D:\experiment>jps 7888 Jps 11704 ShowOwnPID
嗯……这PID没错。
这PID是哪儿来的呢?先看RuntimeMXBean实例的来源,java.lang.management.ManagementFactory:
package java.lang.management; // ... public class ManagementFactory { // ... /** * Returns the managed bean for the runtime system of * the Java virtual machine. * * @return a {@link RuntimeMXBean} object for the Java virtual machine. */ public static RuntimeMXBean getRuntimeMXBean() { return sun.management.ManagementFactory.getRuntimeMXBean(); } // ... }
可以看到它依赖了sun.management.ManagementFactory,于是看看对应的实现:
package sun.management; import java.lang.management.*; // ... import static java.lang.management.ManagementFactory.*; public class ManagementFactory { private ManagementFactory() {}; private static VMManagement jvm; private static RuntimeImpl runtimeMBean = null; public static synchronized RuntimeMXBean getRuntimeMXBean() { if (runtimeMBean == null) { runtimeMBean = new RuntimeImpl(jvm); } return runtimeMBean; } static { AccessController.doPrivileged(new LoadLibraryAction("management")); jvm = new VMManagementImpl(); } // ... }
这里可以发现实现RuntimeMXBean接口的是sun.management.RuntimeImpl。它的实现是:
package sun.management; import java.lang.management.RuntimeMXBean; // ... /** * Implementation class for the runtime subsystem. * Standard and committed hotspot-specific metrics if any. * * ManagementFactory.getRuntimeMXBean() returns an instance * of this class. */ class RuntimeImpl implements RuntimeMXBean { private final VMManagement jvm; private final long vmStartupTime; /** * Constructor of RuntimeImpl class. */ RuntimeImpl(VMManagement vm) { this.jvm = vm; this.vmStartupTime = jvm.getStartupTime(); } public String getName() { return jvm.getVmId(); } // ... }
OK,看到getName()返回的是VMManagement.getVmId()的返回值,再跟过去看:
package sun.management; import java.net.InetAddress; import java.net.UnknownHostException; // ... class VMManagementImpl implements VMManagement { // ... public String getVmId() { int pid = getProcessId(); String hostname = "localhost"; try { hostname = InetAddress.getLocalHost().getHostName(); } catch (UnknownHostException e) { // ignore } return pid + "@" + hostname; } private native int getProcessId(); // ... }
OK,这里可以看到getVmId()返回过来的字符串确实是"pid@hostname"形式的。再追下去,看看native一侧是如何获取PID的话:
j2se/src/share/native/sun/management/VMManagementImpl.c
JNIEXPORT jint JNICALL Java_sun_management_VMManagementImpl_getProcessId (JNIEnv *env, jobject dummy) { jlong pid = jmm_interface->GetLongAttribute(env, NULL, JMM_OS_PROCESS_ID); return (jint) pid; }
于是继续跟,
hotspot/src/share/vm/services/management.cpp
static jlong get_long_attribute(jmmLongAttribute att) { switch (att) { // ... case JMM_OS_PROCESS_ID: return os::current_process_id(); // ... default: return -1; } } JVM_ENTRY(jlong, jmm_GetLongAttribute(JNIEnv *env, jobject obj, jmmLongAttribute att)) if (obj == NULL) { return get_long_attribute(att); } else { // ... } return -1; JVM_END
接下来os::current_process_id()的实现就是每个操作系统不同的了。
在Linux上是:
hotspot/src/os/linux/vm/os_linux.cpp
static pid_t _initial_pid = 0; int os::current_process_id() { // Under the old linux thread library, linux gives each thread // its own process id. Because of this each thread will return // a different pid if this method were to return the result // of getpid(2). Linux provides no api that returns the pid // of the launcher thread for the vm. This implementation // returns a unique pid, the pid of the launcher thread // that starts the vm 'process'. // Under the NPTL, getpid() returns the same pid as the // launcher thread rather than a unique pid per thread. // Use gettid() if you want the old pre NPTL behaviour. // if you are looking for the result of a call to getpid() that // returns a unique pid for the calling thread, then look at the // OSThread::thread_id() method in osThread_linux.hpp file return (int)(_initial_pid ? _initial_pid : getpid()); } // this is called _before_ the most of global arguments have been parsed void os::init(void) { // With LinuxThreads the JavaMain thread pid (primordial thread) // is different than the pid of the java launcher thread. // So, on Linux, the launcher thread pid is passed to the VM // via the sun.java.launcher.pid property. // Use this property instead of getpid() if it was correctly passed. // See bug 6351349. pid_t java_launcher_pid = (pid_t) Arguments::sun_java_launcher_pid(); _initial_pid = (java_launcher_pid > 0) ? java_launcher_pid : getpid(); // ... }
在Windows上是:
static int _initial_pid = 0; int os::current_process_id() { return (_initial_pid ? _initial_pid : _getpid()); } // this is called _before_ the global arguments have been parsed void os::init(void) { _initial_pid = _getpid(); // ... }
=================================================================
好吧其实我是在HotSpot的源码里搜pid然后慢慢找出JMM代码里有调用过os::current_process_id(),然后才一步步向上找到对应的Java API。刚才问毕玄老大有没有见过在Java代码里获取PID的办法,才得知原来以前有人总结过几种办法 ,其中第一个就是本文提到的这个。嘛,需求是一直有的,这种功能自然是早该有人捣腾过了。
转自:http://rednaxelafx.iteye.com/blog/716918
相关推荐
最新版 32位 windows sun jdk7 开发必备
java通过sigar获取进程的相关信息 ,包含各个进程的PID、名称、CPU使用率、所占内存大小等
带sun的jdk 1.8.0_65带sun的jdk 1.8.0_65带sun的jdk 1.8.0_65带sun的jdk 1.8.0_65带sun的jdk 1.8.0_65带sun的jdk 1.8.0_65带sun的jdk 1.8.0_65带sun的jdk 1.8.0_65带sun的jdk 1.8.0_65带sun的jdk 1.8.0_65带sun的jdk...
卸载OpenJDK并安装Sun JDK
功能:获取java进程pid 进程可根据该pid调用exec自杀 注意事项:不能改变PidTool.java所在的包,否则需要重行生成dll。 编译命令中 "-PidTool.dll" 改为 "-FePidTool.dll",我整漏了! 使用方法: 1.javac PidTool...
JDK1.6免安装版本,开发环境搭建;预留一个用来做低版本jdk项目。
jdk源码(包含sun包)jdk源码(包含sun包)jdk源码(包含sun包)jdk源码(包含sun包)jdk源码(包含sun包)jdk源码(包含sun包)jdk源码(包含sun包)jdk源码(包含sun包)
/jdk文件夹下生成一个src.zip,此文件夹对应rt.jar中的java源码,但细心研究后发现rt.jar中sun包下的文件不存在,也就是说sun包下的java源码并没有打包到src.zip中,可以到http://download.java.net/openjdk/jdk7/该...
sun公司提供的开发java的专用文档,可以查看该文档来获取类的相关信息
JDK的种类:最主流的JDK是Sun公司发布的JDK,除了Sun之外,还有很多公司和组织都开发了自己的JDK,例如IBM公司开发的JDK,BEA公司的Jrocket,还有GNU组织开发的JDK等等。其中IBM的JDK包含的JVM(Java Virtual ...
JDK 1.6 SUN公司最新发布 JDK 1.6 SUN公司最新发布JDK 1.6 SUN公司最新发布JDK 1.6 SUN公司最新发布
在使用intellj IDEA查看源代码时,调试进入到sun.nio.ch.FileChannelImpl 类时,发现需要反编译才能查看源代码,在IDEA中已经导入了jdk8的源码,后排查发现sun的源代码实际上不在jdk源码中,后找到一份sun源码包,...
Sun JDK 1.6内存管理--调优篇
Sun JDK 1.6内存管理--调优篇-毕玄
Sun_JDK_1.6内存管理--实现篇-毕玄
jdk sun 开头的源码 有利于分析sun 底层的相关实现, 如channel ,nio等
jdk1.7 自带源码,并补充缺少sun包下的源码,补充源码来自1.7 openjdk
IBM SUN JDK XML解析相关的一点东西,可以使用"IBM JDK API"在百度搜索到的一下信息!
由于默认JDK不包含全部SUN的源码,这个网上找了半天才找到。本来想免费的无奈scdn必须设置资源分数最小是1
自己准备的JAVA8 完整源码(包含Sun包源码),120M大小的,jdk自带src.zip大小为20M,包括sum.misc.*包内的源码。这个用7z打包后13.3M大小。 源码源自:https://github.com/openjdk-mirror/jdk.git的jdk8u/jdk8u/...