Comment un programme Java peut-il obtenir son propre ID de processus?

Réponses:

322

Il n'existe aucun moyen indépendant de la plateforme qui puisse être garanti de fonctionner dans toutes les implémentations jvm. ManagementFactory.getRuntimeMXBean().getName()ressemble à la meilleure solution (la plus proche). Il est court et fonctionne probablement dans toutes les implémentations largement utilisées.

Sur linux + windows, il retourne une valeur comme 12345@hostname( 12345étant l'identifiant du processus). Attention cependant selon les documents , il n'y a aucune garantie sur cette valeur:

Renvoie le nom représentant la machine virtuelle Java en cours d'exécution. La chaîne de nom renvoyée peut être n'importe quelle chaîne arbitraire et une implémentation de machine virtuelle Java peut choisir d'incorporer des informations utiles spécifiques à la plateforme dans la chaîne de nom renvoyée. Chaque machine virtuelle en cours d'exécution peut avoir un nom différent.

Dans Java 9, la nouvelle API de processus peut être utilisée:

long pid = ProcessHandle.current().pid();
Wouter Coekaerts
la source
2
Cette solution est vraiment fragile. Voir une réponse sur Hyperic Sigar ci-dessous.
Michael Klishin
ce pid est bon à écrire sur un fichier de verrouillage comme stackoverflow.com/a/9020391/1422630
Aquarius Power
111

Vous pouvez utiliser JNA . Malheureusement, il n'y a pas encore d'API JNA commune pour obtenir l'ID de processus actuel, mais chaque plate-forme est assez simple:

les fenêtres

Assurez-vous d'avoir jna-platform.jaralors:

int pid = Kernel32.INSTANCE.GetCurrentProcessId();

Unix

Déclarer:

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

Ensuite:

int pid = CLibrary.INSTANCE.getpid();

Java 9

Sous Java 9, la nouvelle API de processus peut être utilisée pour obtenir l'ID de processus actuel. Commencez par saisir un descripteur du processus en cours, puis interrogez le PID:

long pid = ProcessHandle.current().pid();
Luke Quinane
la source
4
+1 Mais je crains que dans un environnement à sécurité limitée, cela ne fonctionne pas (tomcat, WebLogic, etc.).
ATorras
La getpid()solution fonctionne également pour OS X, avec un appel JNA à la bibliothèque "System".
Daniel Widdis
Cependant, je reçois error: cannot find symbolpour jdk9
skytree
56

Voici une méthode de porte dérobée qui pourrait ne pas fonctionner avec toutes les machines virtuelles mais devrait fonctionner à la fois sur Linux et Windows ( exemple original ici ):

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);
Brad Mace
la source
2
très sympa, vient de vérifier qu'il fonctionne aussi bien sur les JRockit que sur les JVM Hotspot.
Drupad Panchal
1
Belle solution de contournement. Je vais supposer qu'il y a une bonne raison pour laquelle cette méthode (et d'autres dans la classe) n'est pas publique et facilement accessible, et je suis curieux de savoir de quoi il s'agit.
fragorl
2
L'équipe Oracle Oracle a annoncé son intention de masquer tous les packages non java (c'est-à-dire sun. *) Je crois à partir de Java 10 (prévu pour 2018 - peut-être Java 9). Si vous avez une implémentation similaire à celle ci-dessus, vous voudrez peut-être trouver une alternative pour que votre code ne se casse pas.
hfontanez
Ne fonctionne pas pour moi non plus car le soleil. * Les packages sont probablement supprimés ou inaccessibles (VMManagement ne peut pas être résolu en un type).
Mike Stoddart
En raison du fonctionnement de la réflexion, l'accès à sun.management. * N'est pas nécessaire. Il suffit d'effectuer la getDeclaredMethodsur l'objet retourné par jvm.get(runtime).
Andrew T Finnell
36

Essayez Sigar . API très étendues. Licence 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();
}
Ashwin Jayaprakash
la source
6
Vous auriez beaucoup plus de votes positifs si vous expliquiez comment utiliser SIGAR pour cela
Brad Mace
1
Le lien est rompu. Vous donnez un exemple d'utilisation, mais existe-t-il une dépendance maven pour cela?
Jules
github.com/hyperic/sigar semble être un emplacement utilisable; cela montre également que c'est du code natif avec des liaisons Java, ce qui peut le rendre moins une solution pour de nombreux contextes.
Zastai
26

La méthode suivante tente d'extraire le 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;
}

Appelez getProcessId("<PID>"), par exemple.

Martin
la source
6
VisualVM utilise un code similaire pour obtenir son PID, consultez com.sun.tools.visualvm.application.jvm.Jvm # ApplicationSupport # createCurrentApplication (). Ce sont les experts, il ressemble donc à une solution fiable et multiplateforme.
Espinosa
@Espinosa VisualVM prend uniquement en charge l'exécution sur une machine virtuelle Java OpenJDK / Oracle / GraalVM (à partir de 2020). Cela signifie qu'ils peuvent faire des hypothèses en conséquence. Si vous faites de même, vous devenez dépendant du fournisseur et votre code peut se casser s'il est exécuté par exemple sur J9.
Thorbjørn Ravn Andersen
24

Pour les anciennes JVM, sous 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";
}
Emmanuel Bourg
la source
52
Si vous allez faire cela, alors faites-le int pid = Integer.parseInt(new File("/proc/self").getCanonicalFile().getName());. Pourquoi les girations supplémentaires?
David Citron
2
Pour les curieux, l'astuce dans le commentaire de @David fonctionne réellement. Quelqu'un peut-il dire pourquoi? Une sorte de magie dans la getCanonicalFile()méthode qui convertit le «moi» en PID?
GreenGiant
7
getCanonicalFile () résout le lien symbolique / proc / self / -> / proc / 1234, essayez ls -al / proc / self
Michael
2
@DavidCitron +1! vous avez raison, je ne pensais pas dans getCanonicalFile :-)
ggrandes
18

Vous pouvez consulter mon projet: JavaSysMon sur GitHub. Il fournit un identifiant de processus et un tas d'autres choses (utilisation du processeur, utilisation de la mémoire) multiplateforme (actuellement Windows, Mac OSX, Linux et Solaris)

Jez Humble
la source
Est-il possible d'obtenir le PID d'un processus démarré par Java? Ou démarrer un processus "à votre façon" pour résoudre ce problème?
Panayotis
17

Depuis Java 9, il existe une méthode Process.getPid () qui renvoie l'ID natif d'un processus:

public abstract class Process {

    ...

    public long getPid();
}

Pour obtenir l'ID de processus du processus Java actuel, on peut utiliser l' ProcessHandleinterface:

System.out.println(ProcessHandle.current().pid());
ZhekaKozlov
la source
2
Pouvez-vous expliquer comment obtenir une instance de processus pour le processus en cours d'exécution dans Java 9?
Augusto
Excellente réponse pour utiliser Java 9 en 2016! Pouvez-vous ajouter un lien vers les javadocs? merci
crazyGuy
8

À Scala:

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

Cela devrait vous fournir une solution de contournement sur les systèmes Unix jusqu'à la sortie de Java 9. (Je sais, la question concernait Java, mais comme il n'y a pas de question équivalente pour Scala, je voulais laisser cela aux utilisateurs de Scala qui pourraient tomber sur la même question.)

Florin T.
la source
7

Pour être complet, il y a un wrapper dans Spring Boot pour le

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

Solution. Si un entier est requis, cela peut se résumer à la ligne unique:

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

Si quelqu'un utilise déjà Spring boot, il / elle peut utiliser org.springframework.boot.ApplicationPid

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

La méthode toString () imprime le pid ou '???'.

Les mises en garde à l'aide de ManagementFactory sont déjà discutées dans d'autres réponses.

l00tr
la source
7
java.lang.management.ManagementFactory.getRuntimeMXBean().getName().split("@")[0]
Markus
la source
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;
}
Jaskey
la source
5

Le dernier que j'ai trouvé est qu'il existe une propriété système appelée sun.java.launcher.pidqui est disponible au moins sur Linux. Mon plan est de l'utiliser et s'il n'est pas trouvé d'utiliser le JMX bean.

Jared
la source
Dans mon cas avec Ubuntu 16.04 et Java 8, il renvoie null
david.perez
4

Cela dépend d'où vous cherchez les informations.

Si vous recherchez les informations de la console, vous pouvez utiliser la commande jps. La commande donne une sortie similaire à la commande Unix ps et est livrée avec le JDK car je crois que 1.5

Si vous cherchez à partir du processus, le RuntimeMXBean (comme l'a dit Wouter Coekaerts) est probablement votre meilleur choix. La sortie de getName () sous Windows à l'aide de Sun JDK 1.6 u7 se présente sous la forme [PROCESS_ID] @ [MACHINE_NAME]. Vous pouvez cependant essayer d'exécuter jps et d'analyser le résultat à partir de cela:

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

S'il est exécuté sans options, la sortie doit être l'ID du processus suivi du nom.

Ryan P
la source
1
L'outil JPS utilise la bibliothèque jvmstat, qui fait partie de tools.jar. Consultez mon exemple ou consultez le code source JPS: grepcode.com/file_/repository.grepcode.com/java/root/jdk/… . Il n'est pas nécessaire d'appeler JPS en tant que processus externe, utilisez directement la bibliothèque jvmstat.
Espinosa
4

Il s'agit du code JConsole et potentiellement utilisé par jps et VisualVM. Il utilise des classes de sun.jvmstat.monitor.*package, 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;
    }
}

Il y a peu de captures:

  • La tool.jarest une bibliothèque distribuée avec Oracle JDK mais pas JRE!
  • Vous ne pouvez pas obtenir tool.jardu repo Maven; le configurer avec Maven est un peu délicat
  • Le tool.jarcontient probablement du code dépendant de la plate-forme (natif?) Donc il n'est pas facilement distribuable
  • Il fonctionne en supposant que toutes les applications JVM (locales) en cours d'exécution sont "contrôlables". Il semble que depuis Java 6, toutes les applications le sont généralement (sauf si vous configurez activement ci-contre)
  • Cela ne fonctionne probablement que pour Java 6+
  • Eclipse ne publie pas de classe principale, donc vous n'obtiendrez pas facilement Eclipse PID. Bug dans MonitoredVmUtil?

MISE À JOUR: Je viens de vérifier que JPS utilise de cette façon, c'est-à-dire la bibliothèque Jvmstat (qui fait partie de tool.jar). Il n'est donc pas nécessaire d'appeler JPS en tant que processus externe, appelez directement la bibliothèque Jvmstat comme mon exemple le montre. Vous pouvez également obtenir la liste de toutes les JVM qui s'exécutent sur localhost de cette façon. Voir le code source JPS :

Espinosa
la source
si mainClass.getName () ne fonctionne pas, essayez d'utiliser mainClass.getCanonicalName ();
Narendra Parmar
3

J'ajoute cela, à d'autres solutions.

avec Java 10, pour obtenir process id

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

Vous pouvez essayer getpid()dans JNR-Posix .

Il a un wrapper Windows POSIX qui appelle getpid () hors de libc.

kervin
la source
1

Je sais que c'est un vieux fil, mais je voulais appeler cette API pour obtenir le PID (ainsi que d'autres manipulations du processus Java au moment de l'exécution) est ajoutée à la classe Process dans JDK 9: http: // openjdk. java.net/jeps/102

Brandon Heck
la source
9
Wow, c'était rapide. Cela n'a pris que sept ans environ! 😃
Dmitry Shechtman
1

J'ai trouvé une solution qui peut être un peu un cas de bord et je ne l'ai pas essayée sur un autre système d'exploitation que Windows 10, mais je pense qu'il vaut la peine de le remarquer.

Si vous vous retrouvez à travailler avec J2V8 et nodejs, vous pouvez exécuter une simple fonction javascript vous renvoyant le pid du processus java.

Voici un exemple:

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

Voici ma solution:

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;
    }
PartialData
la source
Cela ne vérifie pas si pid est en cours d'utilisation, mais si pid est égal au processus actuel pid
c0der
Quelle est la bonne solution pour pouvoir mettre à jour mon code?
PartialData
-6

C'est ce que j'ai utilisé lorsque j'avais des exigences similaires. Cela détermine correctement le PID du processus Java. Laissez votre code java générer un serveur sur un numéro de port prédéfini, puis exécutez les commandes du système d'exploitation pour découvrir l'écoute PID sur le port. Pour Linux

netstat -tupln | grep portNumber
Subhash
la source
3
Si vous appelez des scripts shell, vous pourriez aussi bien faire quelque chose de plus simple comme bash -c 'echo $PPID'ou les réponses
Rich