`
我是老威
  • 浏览: 26418 次
  • 性别: Icon_minigender_1
  • 来自: 上海
社区版块
存档分类
最新评论

Sun的JDK里获取当前进程ID的方法(hack)【转】

阅读更多

Java标准库里常见的公有API确实是没有获取当前进程的ID的方法,有时候挺郁闷的,就是需要自己的PID。
于是有各种workaround,其中有很靠谱的通过JNI调用外部的C/C++扩展,然后调用操作系统提供的相应API去获取PID;也有些不怎么靠谱的hack。这里要介绍的就是后者之一,只在Sun JDK或兼容的JDK上有效的方法。

代码例子如下:

Java代码
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。
运行这个程序可以看到类似以下的输出:

Command prompt代码
D:\experiment>java ShowOwnPID
pid: 11704


这个时候再跑一个jps来看看当前都有哪些Java进程的话,可以看到:

Command prompt代码
D:\experiment>jps
7888 Jps
11704 ShowOwnPID


嗯……这PID没错。

这PID是哪儿来的呢?先看RuntimeMXBean实例的来源,java.lang.management.ManagementFactory:

Java代码
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,于是看看对应的实现:

Java代码
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。它的实现是:

Java代码
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()的返回值,再跟过去看:

Java代码
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

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

C++代码
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

C++代码
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上是:

C++代码
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

分享到:
评论

相关推荐

    sun jdk7 32位windows

    最新版 32位 windows sun jdk7 开发必备

    java获取各进程的信息

    `:获取当前系统中的所有进程ID。 - 对每个PID执行以下操作: - 调用`Ps.getInfo(sigarProxy, pid);`获取进程信息。 - 计算CPU使用率:`ProcCpu cpu = sigarProxy.getProcCpu(pid);` - 将CPU使用率添加到进程...

    jdk1.8 sun源码

    在JDK 1.8版本中,虽然已经包含了大部分核心类库的源代码,但某些特定的Sun Microsystems(后被Oracle收购)实现的内部类或模块,如JNI(Java Native Interface)和一些性能优化的代码,通常并不公开。这些内部实现...

    sun java jdk

    ### 关于Sun Java JDK的知识点 #### 一、Sun Java JDK简介 Sun Java JDK(Java Development Kit)是由Sun Microsystems公司提供的官方Java开发工具包。它包含了编写、编译和调试Java应用程序所需的所有软件和文档...

    卸载OpenJDK并安装Sun JDK

    ### 卸载OpenJDK并安装Sun JDK #### 一、卸载OpenJDK 在进行Sun JDK的安装之前,确保系统中没有已存在的JDK版本是非常重要的,尤其是OpenJDK,因为它可能会与新安装的Sun JDK冲突。下面将详细介绍如何在Linux环境...

    带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 1.8.0_65带sun的jdk...

    jdk源码-补充缺少sun包下的源码

    《深入解析JDK1.7源码:补全sun包下的源码》 在Java开发过程中,理解JDK源码是提升技术深度的关键步骤。JDK1.7版本的源码提供了对Java语言核心库的深入洞察,而sun包下的源码更是其中的重要组成部分,因为它们包含...

    JDK1.8 sun 包源码

    /jdk文件夹下生成一个src.zip,此文件夹对应rt.jar中的java源码,但细心研究后发现rt.jar中sun包下的文件不存在,也就是说sun包下的java源码并没有打包到src.zip中,可以到http://download.java.net/openjdk/jdk7/该...

    IBM SUN JDK XML解析相关

    SAX解析器在两个JDK中同样提供`org.xml.sax.helpers.DefaultHandler`作为基础事件处理器,通过实现回调方法如`startElement()`、`endElement()`来处理XML事件。例如: ```java SAXParserFactory factory = ...

    java获取当前windows进程pid

    功能:获取java进程pid 进程可根据该pid调用exec自杀 注意事项:不能改变PidTool.java所在的包,否则需要重行生成dll。 编译命令中 "-PidTool.dll" 改为 "-FePidTool.dll",我整漏了! 使用方法: 1.javac PidTool...

    jdk包含sun包

    jdk源码(包含sun包)jdk源码(包含sun包)jdk源码(包含sun包)jdk源码(包含sun包)jdk源码(包含sun包)jdk源码(包含sun包)jdk源码(包含sun包)jdk源码(包含sun包)

    Sun_JDK_1.6内存管理--实现篇-毕玄

    标题与描述中的关键词“Sun_JDK_1.6内存管理--实现篇”指向了Java虚拟机(JVM)中Sun JDK 1.6版本的内存管理机制及其具体实现细节。在这一部分,我们将会深入探讨Sun JDK 1.6如何处理内存分配、垃圾收集以及其他优化...

    SUN JDK1.6 免安装

    SUN JDK1.6,也称为Java SE 6,是Java平台标准版的一个重要版本,它包含了编译器、JVM(Java虚拟机)、调试器以及其他开发工具。"免安装版本"意味着这个JDK不需要通过传统的安装程序来设置,而是可以直接解压到指定...

    Sun JDK 1.6内存管理--调优篇

    5. 管理PermGen空间:在Sun JDK 1.6中,方法区(Method Area)也被称为 PermGen,需关注-XX:MaxPermSize以避免Class定义过多导致的Full GC。 6. 监控和诊断:使用JVisualVM、jconsole等工具监控JVM内存状态,通过-...

    JDK1.7,JDK的种类:最主流的JDK是Sun公司发布的JDK

    JDK的种类:最主流的JDK是Sun公司发布的JDK,除了Sun之外,还有很多公司和组织都开发了自己的JDK,例如IBM公司开发的JDK,BEA公司的Jrocket,还有GNU组织开发的JDK等等。其中IBM的JDK包含的JVM(Java Virtual ...

    jdk1.8源码包含sun

    《深入解析JDK1.8源码中的"sun"包》 在Java开发领域,对JDK源码的深入理解是提升技术能力的关键步骤。JDK1.8作为广泛使用的版本,其源码包含了丰富的实现细节,特别是"sun"包,它承载了许多核心功能和内部实现。...

    CentOS卸载OpenJDK并安装Sun JDK

    ### CentOS卸载OpenJDK并安装Sun JDK:深入解析与操作指南 #### 一、理解OpenJDK与Sun JDK **OpenJDK**是开源Java平台的实现,它基于Sun Microsystems发布的HotSpot虚拟机和Java类库。OpenJDK自Java SE 7开始成为...

    sun jdk源代码

    在使用intellj IDEA查看源代码时,调试进入到sun.nio.ch.FileChannelImpl 类时,发现需要反编译才能查看源代码,在IDEA中已经导入了jdk8的源码,后排查发现sun的源代码实际上不在jdk源码中,后找到一份sun源码包,...

    jdk sun 开头的源码

    在JDK中,"sun"开头的源码包是Oracle(原Sun Microsystems)公司提供的核心API,它们包含了Java平台的许多底层实现,这些源码对于深入理解Java的内部机制至关重要。 "sun"前缀的源码主要涉及以下几个关键领域: 1....

    jdk8u65+openjdk的sun包

    在这个压缩包“jdk8u65+openjdk的sun包”中,我们主要关注的是两个版本的Java JDK:JDK 8 Update 65 和 OpenJDK。 **JDK 8 Update 65** JDK 8 Update 65 是Oracle公司发布的Java 8的一个更新版本。这个版本修复了...

Global site tag (gtag.js) - Google Analytics