Friday 28 June 2013

How to get Process ID for any JVM application?

How to get Process ID for any JVM application? How to get PID for current process?

There is plenty of solutions on Stackoverflow, mostly involving operating system hacks [1], or libraries with native code [2] or ManagementFactory.getRuntimeMXBean() based solutions [3], limited to current process only.

I would like to introduce another solution, JConsole, and potentially jps and VisualVM uses. It is based on classes from sun.jvmstat.monitor.* package, from tool.jar.

Jvmstat solution

This simple program gets list of all running JVMs on localhost, with their PIDs, and then extracting their main their classes comparing them to given main class name, returning PID when they match.

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;
    }
}

There are few catches:
  • The tool.jar is a library distributed with Oracle JDK but not JRE!
  • You cannot get tool.jar from Maven repo; configure it with Maven is a bit tricky, see [6].
  • The tool.jar probably contains platform dependent (native?) code so it is not easily distributable
  • It runs under assumption that all (local) running JVM apps are "monitorable". It looks like that from Java 6 all apps generally are (unless you actively configure opposite)
  • It probably works only for Java 6+
  • Eclipse does not publish main class, so you will not get Eclipse PID easily. It is probably because Eclipse is a JVM application, but is launched as eclipse.exe, a native executable somehow encapsulating JVM. You yould have to employ more sophisticated measures, like VisualVM does, to recognize Eclipse like checking characteristic JVM properties.

Comments on another questionable but popular solution

There is one more popular solution, mentioned for example here [4], and that is to use Process implementation class and get PID from its internal private data. 
Process process = Runtime.getRuntime().exec(command);
and then check returned implementation; allegedly on Unix it is java.lang.UnixProcess which has a private field called pid. But on Windows Process implementation returned is java.lang.ProcessImpl and it has no such field, no notion of PID. This is not a cross platform solution, besides relying on forcefully accessed private fields is always hackish and can stop working in the next Java release.

 Links

[1] http://www.jroller.com/santhosh/entry/get_current_java_process_id
[2] https://support.hyperic.com/display/SIGAR/Home
[3] http://stackoverflow.com/questions/35842/how-can-a-java-program-get-its-own-process-id
[4] http://stackoverflow.com/a/4750632/1185845
[6] http://stackoverflow.com/questions/3080437/jdk-tools-jar-as-maven-dependency  

1 comment:

  1. Not surprisingly, Oracle also discourage using of sun packages, like sun.jvmstat.monitor, see here http://www.oracle.com/technetwork/java/faq-sun-packages-142232.html
    But I still consider using sun.jvmstat.monitor approach the least fragile, compared to rely on casting Process on any particular implementation like UnixProcess and more portable then calling external tools from the OS.

    ReplyDelete