¿Cómo puede un programa Java obtener su propia ID de proceso?


Respuestas:


322

No existe una forma independiente de la plataforma que pueda garantizarse que funcione en todas las implementaciones de jvm. ManagementFactory.getRuntimeMXBean().getName()Parece la mejor solución (más cercana). Es breve, y probablemente funciona en todas las implementaciones en uso amplio.

En linux + windows devuelve un valor como 12345@hostname( 12345siendo el id del proceso). Sin embargo, tenga en cuenta que según los documentos , no hay garantías sobre este valor:

Devuelve el nombre que representa la máquina virtual Java en ejecución. La cadena de nombre devuelta puede ser cualquier cadena arbitraria y una implementación de máquina virtual Java puede elegir incrustar información útil específica de la plataforma en la cadena de nombre devuelta. Cada máquina virtual en ejecución podría tener un nombre diferente.

En Java 9 , se puede utilizar la nueva API de proceso :

long pid = ProcessHandle.current().pid();

2
Esta solución es realmente frágil. Vea una respuesta sobre Hyperic Sigar a continuación.
Michael Klishin

que pid es bueno escribir en un archivo de bloqueo como stackoverflow.com/a/9020391/1422630
Aquarius Power

111

Podrías usar JNA . Desafortunadamente, todavía no hay una API JNA común para obtener la ID de proceso actual, pero cada plataforma es bastante simple:

Ventanas

Asegúrate de tener jna-platform.jarentonces:

int pid = Kernel32.INSTANCE.GetCurrentProcessId();

Unix

Declarar:

private interface CLibrary extends Library {
    CLibrary INSTANCE = (CLibrary) Native.loadLibrary("c", CLibrary.class);   
    int getpid ();
}

Entonces:

int pid = CLibrary.INSTANCE.getpid();

Java 9

En Java 9, la nueva API de proceso se puede utilizar para obtener la ID del proceso actual. Primero, toma un identificador del proceso actual, luego consulta el PID:

long pid = ProcessHandle.current().pid();

44
+1 Pero me temo que en un entorno con restricciones de seguridad no debería funcionar (tomcat, WebLogic, etc.).
ATorras

La getpid()solución también funciona para OS X, con una llamada JNA a la biblioteca "Sistema".
Daniel Widdis

Sin embargo, me sale error: cannot find symbolpara jdk9
skytree

56

Aquí hay un método de puerta trasera que podría no funcionar con todas las máquinas virtuales, pero debería funcionar tanto en Linux como en Windows ( ejemplo original aquí ):

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

2
muy bueno, solo verifiqué que funciona tanto en JRockit como en JVM de Hotspot.
Drupad Panchal

1
Buena solución. Asumiré que hay una buena razón por la cual este método (y otros en la clase) no son públicos y de fácil acceso, y tengo curiosidad por saber de qué se trata.
fragorl

2
El equipo de Oracle Java ha anunciado que tienen la intención de ocultar todos los paquetes que no sean Java (es decir, sun. *). Creo que comenzará con Java 10 (programado para 2018, tal vez Java 9). Si tiene una implementación similar a la anterior, es posible que desee encontrar una alternativa para que su código no se rompa.
hfontanez

Tampoco funciona para mí, ya que los paquetes sun. * Probablemente se eliminan o son inaccesibles (VMManagement no se puede resolver a un tipo).
Mike Stoddart el

Debido a la forma en que funciona la reflexión, no se necesita acceso a sun.management. *. Simplemente realice el getDeclaredMethoden el Objeto devuelto por jvm.get(runtime).
Andrew T Finnell

36

Prueba con Sigar . API muy extensas. Apache 2 licencia.

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

66
Tendría muchos más votos a favor si explicara cómo usar SIGAR para esto
Brad Mace

1
El enlace está roto. Da un ejemplo de cómo usar esto, pero ¿hay alguna dependencia de Maven para ello?
Jules

github.com/hyperic/sigar parece ser una ubicación utilizable; Esto también muestra que es un código nativo con enlaces Java, lo que puede hacer que sea menos una solución para muchos contextos.
Zastai

26

El siguiente método intenta extraer el PID de 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;
}

Solo llame getProcessId("<PID>"), por ejemplo.


66
VisualVM usa un código similar para obtener el PID propio, verifique com.sun.tools.visualvm.application.jvm.Jvm # ApplicationSupport # createCurrentApplication (). Ellos son los expertos, por lo que parece una solución confiable y multiplataforma.
Espinosa

@Espinosa VisualVM solo admite la ejecución en OpenJDK / Oracle / GraalVM JVM (a partir de 2020). Esto significa que pueden hacer suposiciones en consecuencia. Si hace lo mismo, dependerá del proveedor y su código puede romperse si se ejecuta, por ejemplo, en J9.
Thorbjørn Ravn Andersen

24

Para JVM anteriores, en 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";
}

52
Si vas a hacer eso, entonces solo hazlo int pid = Integer.parseInt(new File("/proc/self").getCanonicalFile().getName());. ¿Por qué los giros extra?
David Citron

2
Para los curiosos, el truco en el comentario de @David realmente funciona. ¿Alguien puede decir por qué? ¿Algún tipo de magia en el getCanonicalFile()método que convierte "self" al PID?
GreenGiant

77
getCanonicalFile () resuelve el enlace simbólico / proc / self / -> / proc / 1234, prueba ls -al / proc / self
Michael

2
@DavidCitron +1! tienes razón, no pensé en getCanonicalFile :-)
ggrandes

18

Puedes ver mi proyecto: JavaSysMon en GitHub. Proporciona id de proceso y un montón de otras cosas (uso de CPU, uso de memoria) multiplataforma (actualmente Windows, Mac OSX, Linux y Solaris)


¿Es posible obtener el PID de un proceso iniciado por Java? ¿O iniciar un proceso "a su manera" para solucionar este problema?
Panayotis

17

Desde Java 9 hay un método Process.getPid () que devuelve la ID nativa de un proceso:

public abstract class Process {

    ...

    public long getPid();
}

Para obtener la ID del proceso del proceso Java actual, se puede usar la ProcessHandleinterfaz:

System.out.println(ProcessHandle.current().pid());

2
¿Puede explicar cómo obtener una instancia de Proceso para el proceso actual en ejecución en Java 9?
Augusto

¡Gran respuesta para usar Java 9 en 2016! ¿Puedes agregar un enlace a los javadocs? gracias
crazyGuy

8

En Scala:

import sys.process._
val pid: Long = Seq("sh", "-c", "echo $PPID").!!.trim.toLong

Esto debería darle una solución alternativa en los sistemas Unix hasta que se lance Java 9. (Lo sé, la pregunta era sobre Java, pero como no hay una pregunta equivalente para Scala, quería dejar esto para los usuarios de Scala que podrían tropezar con la misma pregunta).


7

Para completar, hay un contenedor en Spring Boot para

String jvmName = ManagementFactory.getRuntimeMXBean().getName();
return jvmName.split("@")[0];

solución. Si se requiere un número entero, esto se puede resumir en una línea:

int pid = Integer.parseInt(ManagementFactory.getRuntimeMXBean().getName().split("@")[0]);

Si alguien ya usa Spring boot, él / ella puede usar org.springframework.boot.ApplicationPid

ApplicationPid pid = new ApplicationPid();
pid.toString();

El método toString () imprime el pid o '???'.

Las advertencias que usan ManagementFactory ya se analizan en otras respuestas.


7
java.lang.management.ManagementFactory.getRuntimeMXBean().getName().split("@")[0]

6
public static long getPID() {
    String processName = java.lang.management.ManagementFactory.getRuntimeMXBean().getName();
    if (processName != null && processName.length() > 0) {
        try {
            return Long.parseLong(processName.split("@")[0]);
        }
        catch (Exception e) {
            return 0;
        }
    }

    return 0;
}

5

Lo último que he encontrado es que hay una propiedad del sistema llamada sun.java.launcher.pidque está disponible al menos en Linux. Mi plan es usar eso y, si no se encuentra, usar el JMX bean.


En mi caso con Ubuntu 16.04 y Java 8, devuelve nulo
david.perez

4

Depende de dónde esté buscando la información.

Si está buscando la información de la consola, puede usar el comando jps. El comando da una salida similar al comando Unix ps y viene con el JDK ya que creo que 1.5

Si está buscando en el proceso, RuntimeMXBean (como dijo Wouter Coekaerts) es probablemente su mejor opción. El resultado de getName () en Windows con Sun JDK 1.6 u7 tiene el formato [PROCESS_ID] @ [MACHINE_NAME]. Sin embargo, podría intentar ejecutar jps y analizar el resultado a partir de eso:

String jps = [JDK HOME] + "\\bin\\jps.exe";
Process p = Runtime.getRuntime().exec(jps);

Si se ejecuta sin opciones, la salida debería ser la identificación del proceso seguida del nombre.


1
La herramienta JPS utiliza la biblioteca jvmstat, parte de tools.jar. Consulte mi ejemplo o vea el código fuente JPS: grepcode.com/file_/repository.grepcode.com/java/root/jdk/… . No es necesario llamar a JPS como proceso externo, use la biblioteca jvmstat directamente.
Espinosa

4

Este es el código JConsole, y potencialmente utiliza jps y VisualVM. Utiliza clases de sun.jvmstat.monitor.*paquete, de 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;
    }
}

Hay pocas capturas:

  • los tool.jar Es una biblioteca distribuida con Oracle JDK pero no con JRE!
  • No puedes conseguir tool.jar del repositorio de Maven; configurarlo con Maven es un poco complicado
  • los tool.jar probablemente contiene código dependiente de la plataforma (nativo?) Por lo que no es fácilmente distribuibles
  • Se ejecuta bajo el supuesto de que todas las aplicaciones JVM (locales) que se ejecutan son "monitoreables". Parece que desde Java 6 todas las aplicaciones generalmente lo son (a menos que configure activamente lo contrario)
  • Probablemente solo funcione para Java 6+
  • Eclipse no publica la clase principal, por lo que no obtendrá Eclipse PID fácilmente ¿Error en MonitoredVmUtil?

ACTUALIZACIÓN: Acabo de comprobar que JPS usa de esta manera, es decir, la biblioteca Jvmstat (parte de tool.jar). Por lo tanto, no es necesario llamar a JPS como proceso externo, llame a la biblioteca Jvmstat directamente como lo muestra mi ejemplo. También puede obtener la lista de todas las JVM que se ejecutan en localhost de esta manera. Ver código fuente JPS :


si mainClass.getName () no funciona, intente utilizar mainClass.getCanonicalName ();
Narendra Parmar

3

Estoy agregando esto, a otras soluciones.

con Java 10, para obtener process id

final RuntimeMXBean runtime = ManagementFactory.getRuntimeMXBean();
final long pid = runtime.getPid();
out.println("Process ID is '" + pid);


1

Puedes probar getpid()en JNR-Posix .

Tiene un contenedor POSIX de Windows que invoca getpid () fuera de libc.



1

Encontré una solución que puede ser un poco marginal y no la probé en otro sistema operativo que no sea Windows 10, pero creo que vale la pena notarlo.

Si se encuentra trabajando con J2V8 y nodejs, puede ejecutar una función javascript simple que le devolverá el pid del proceso java.

Aquí hay un ejemplo:

public static void main(String[] args) {
    NodeJS nodeJS = NodeJS.createNodeJS();
    int pid = nodeJS.getRuntime().executeIntegerScript("process.pid;\n");
    System.out.println(pid);
    nodeJS.release();
}

-1

Aquí está mi solución:

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

Esto no verifica si pid está en uso, pero si pid es igual al proceso actual pid
c0der

¿Cuál es la solución correcta para poder actualizar mi código?
PartialData

-6

Esto es lo que usé cuando tenía un requisito similar. Esto determina el PID del proceso Java correctamente. Deje que su código Java genere un servidor en un número de puerto predefinido y luego ejecute comandos del sistema operativo para descubrir el PID que escucha en el puerto. Para Linux

netstat -tupln | grep portNumber

3
Si está llamando scripts de shell, también podría hacer algo más simple bash -c 'echo $PPID'o las respuestas
Rich
Al usar nuestro sitio, usted reconoce que ha leído y comprende nuestra Política de Cookies y Política de Privacidad.
Licensed under cc by-sa 3.0 with attribution required.