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

StackOverflow https://stackoverflow.com/questions/35842

  •  09-06-2019
  •  | 
  •  

Question

Comment obtenir l’identifiant de mon processus Java ?

Je sais qu'il existe plusieurs hacks dépendants de la plate-forme, mais je préférerais une solution plus générique.

Était-ce utile?

La solution

Il n'existe aucune méthode indépendante de la plate-forme dont le fonctionnement puisse être garanti dans toutes les implémentations JVM.ManagementFactory.getRuntimeMXBean().getName() semble être la meilleure solution (la plus proche).C'est court, et probablement fonctionne dans toutes les implémentations largement utilisées.

Sous Linux+Windows, il renvoie une valeur comme 12345@hostname (12345 étant l'identifiant du processus).Attention quand même à ça d'après 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 noms renvoyée peut être n'importe quelle chaîne arbitraire et une implémentation de la machine virtuelle Java peut choisir d'intégrer des informations utiles spécifiques à la plate-forme dans la chaîne de noms renvoyée.Chaque machine virtuelle en cours d'exécution pourrait avoir un nom différent.

En Java 9 le nouveau API de processus peut être utilisé:

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

Autres conseils

Vous pourriez utiliser JNA.Malheureusement, il n'existe 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 que vous avez jna-platform.jar alors:

int pid = Kernel32.INSTANCE.GetCurrentProcessId();

Unix

Déclarer:

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

Alors:

int pid = CLibrary.INSTANCE.getpid();

Java9

Sous Java 9 le nouveau API de processus peut être utilisé pour obtenir l’ID de processus actuel.Commencez par saisir le processus en cours, puis interrogez le PID :

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

Voici une méthode de porte dérobée qui pourrait ne fonctionne pas avec toutes les machines virtuelles mais devrait fonctionner à la fois sous 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);

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

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

Il suffit d'appeler getProcessId("<PID>"), par exemple.

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

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

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 du processus Java actuel, vous pouvez utiliser le ProcessHandle interface:

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

En Scala :

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

Cela devrait vous donner 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.)

Pour être complet, il y a un wrapper dans Botte de printemps pour le

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

solution.Si un nombre entier est requis, cela peut se résumer à une seule ligne :

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

Si quelqu'un utilise déjà Spring Boot, il pourrait utiliser org.springframework.boot.ApplicationPid

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

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

Les mises en garde concernant l'utilisation de ManagementFactory sont déjà abordées dans d'autres réponses.

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

La dernière fois que j'ai découvert, c'est qu'il existe un propriété du système appelé sun.java.launcher.pid qui est disponible au moins sous Linux.Mon plan est de l'utiliser et s'il n'est pas trouvé, d'utiliser le JMX bean.

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

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

Si vous recherchez les informations depuis la console, vous pouvez utiliser la commande jps.La commande donne un résultat similaire à la commande Unix ps et est livrée avec le JDK depuis je crois 1.5

Si vous recherchez le processus, le RuntimeMXBean (comme le dit Wouter Coekaerts) est probablement votre meilleur choix.Le résultat 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 analyser le résultat :

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

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

Basé sur Ashwin Jayaprakash répondre (+1) sur l'Apache 2.0 sous licence SIGAR, voici comment je l'utilise pour obtenir uniquement le PID du processus en cours :

import org.hyperic.sigar.Sigar;

Sigar sigar = new Sigar();
long pid = sigar.getPid();
sigar.close();

Même si cela ne fonctionne pas sur toutes les plateformes, cela fonctionne sur Linux, Windows, OS X et diverses plates-formes Unix répertoriées ici.

Il s'agit du code utilisé par JConsole et potentiellement par jps et VisualVM.Il utilise des cours desun.jvmstat.monitor.* paquet, à partir 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 quelques pièges :

  • Le tool.jar est une bibliothèque distribuée avec Oracle JDK mais pas JRE !
  • Vous ne pouvez pas obtenir tool.jar du dépôt Maven ;le configurer avec Maven est un peu délicat
  • Le tool.jar Contient probablement le code dépendant de la plate-forme (natif?)
  • Il fonctionne en supposant que toutes les applications JVM en cours d'exécution (locales) sont "surveillables".Il semble que de Java 6 toutes les applications sont généralement (sauf si vous configurez activement l'opposé)
  • Cela ne fonctionne probablement que pour Java 6+
  • Eclipse ne publie pas la classe principale, vous n'obtiendrez donc pas Eclipse PID facilement bug dans surveildvmutil?

MISE À JOUR:Je viens de vérifier que JPS utilise cette méthode, 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 le montre mon exemple.Vous pouvez également obtenir la liste de toutes les JVM exécutées sur localhost de cette façon.Voir JPS code source:

Tu peux essayer getpid() dans JNR-Posix.

Il dispose d'un wrapper Windows POSIX qui appelle getpid() hors de la libc.

Je sais que c'est un vieux fil de discussion, mais je voulais signaler que l'API permettant d'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

J'ai trouvé une solution qui peut être un peu marginale et je ne l'ai pas essayée sur un autre système d'exploitation que Windows 10, mais je pense que cela vaut la peine d'être remarqué.

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

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

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

C'est ce que j'ai utilisé lorsque j'avais une exigence similaire.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 connaître le PID en écoute sur le port.Pour Linux

netstat -tupln | grep portNumber
Licencié sous: CC-BY-SA avec attribution
Non affilié à StackOverflow
scroll top