Domanda

Come posso ottenere l'ID del mio processo Java?

So che esistono diversi hack dipendenti dalla piattaforma, ma preferirei una soluzione più generica.

È stato utile?

Soluzione

Non esiste un modo indipendente dalla piattaforma che possa garantire il funzionamento in tutte le implementazioni jvm.ManagementFactory.getRuntimeMXBean().getName() sembra la soluzione migliore (più vicina).È breve e probabilmente funziona in ogni implementazione ampiamente utilizzata.

Su Linux+Windows restituisce un valore simile 12345@hostname (12345 essendo l'ID del processo).Attenzione però secondo i documenti, non ci sono garanzie su questo valore:

Restituisce il nome che rappresenta la Java virtual machine in esecuzione.La stringa di nome restituita può essere qualsiasi stringa arbitraria e un'implementazione di macchina virtuale Java può scegliere di incorporare informazioni utili specifiche della piattaforma nella stringa di nome restituita.Ogni macchina virtuale in esecuzione potrebbe avere un nome diverso.

In Giava9 il nuovo processo API può essere utilizzata:

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

Altri suggerimenti

Potresti usare JNA.Sfortunatamente non esiste ancora un'API JNA comune per ottenere l'ID del processo corrente, ma ogni piattaforma è piuttosto semplice:

finestre

Assicurati di avere jna-platform.jar Poi:

int pid = Kernel32.INSTANCE.GetCurrentProcessId();

Unix

Dichiarare:

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

Poi:

int pid = CLibrary.INSTANCE.getpid();

Giava9

Sotto Java 9 il nuovo processo API può essere utilizzato per ottenere l'ID del processo corrente.Per prima cosa prendi un handle per il processo corrente, quindi interroghi il PID:

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

Ecco un metodo backdoor che Potrebbe non funziona con tutte le macchine virtuali ma dovrebbe funzionare sia su Linux che su Windows (esempio originale qui):

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

Tentativo Sigaro .API molto estese.Licenza Apache2.

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

Il seguente metodo tenta di estrarre il PID da 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;
}

Chiama soltanto getProcessId("<PID>"), ad esempio.

Per la JVM precedente, in 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";
}

Puoi dare un'occhiata al mio progetto: JavaSysMon su GitHub.Fornisce l'ID del processo e una serie di altre cose (utilizzo della CPU, utilizzo della memoria) multipiattaforma (attualmente Windows, Mac OSX, Linux e Solaris)

A partire da Java 9 esiste un metodo Process.getPid() che restituisce l'ID nativo di un processo:

public abstract class Process {

    ...

    public long getPid();
}

Per ottenere l'ID del processo Java corrente è possibile utilizzare il file ProcessHandle interfaccia:

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

A Scala:

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

Questo dovrebbe darti una soluzione alternativa sui sistemi Unix fino al rilascio di Java 9.(Lo so, la domanda riguardava Java, ma poiché non esiste una domanda equivalente per Scala, volevo lasciarla agli utenti Scala che potrebbero inciampare nella stessa domanda.)

Per completezza è presente un involucro Stivale primaverile per il

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

soluzione.Se è richiesto un numero intero, questo può essere riassunto in una riga:

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

Se qualcuno usa già Spring Boot, potrebbe usarlo org.springframework.boot.ApplicationPid

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

Il metodo toString() stampa il pid o '???'.

Gli avvertimenti sull'utilizzo di ManagementFactory sono già discussi in altre risposte.

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

L'ultima che ho scoperto è che esiste un file proprietà del sistema chiamato sun.java.launcher.pid che è disponibile almeno su Linux.Il mio piano è di usarlo e, se non viene trovato, usare il file JMX bean.

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

Dipende da dove stai cercando le informazioni.

Se stai cercando le informazioni dalla console puoi usare il comando jps.Il comando fornisce un output simile al comando Unix ps e viene fornito con JDK poiché credo che 1.5

Se stai guardando il processo, RuntimeMXBean (come detto da Wouter Coekaerts) è probabilmente la scelta migliore.L'output di getName() su Windows utilizzando Sun JDK 1.6 u7 è nel formato [PROCESS_ID]@[MACHINE_NAME].Potresti comunque provare a eseguire jps e analizzare il risultato da quello:

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

Se eseguito senza opzioni, l'output dovrebbe essere l'ID del processo seguito dal nome.

Basato su Ashwin Jayaprakash risposta (+1) A proposito di Apache 2.0 con licenza SIGAR, ecco come lo utilizzo per ottenere solo il PID del processo corrente:

import org.hyperic.sigar.Sigar;

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

Anche se non funziona su tutte le piattaforme, funziona su Linux, Windows, OS X e varie piattaforme Unix elencate qui.

Questo è il codice utilizzato da JConsole e potenzialmente da jps e VisualVM.Utilizza classi dasun.jvmstat.monitor.* pacchetto, da 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;
    }
}

Ci sono poche catture:

  • IL tool.jar è una libreria distribuita con Oracle JDK ma non JRE!
  • Non puoi ottenere tool.jar dal repository Maven;configurarlo con Maven è un po' complicato
  • IL tool.jar probabilmente contiene codice dipendente dalla piattaforma (nativa?) Quindi non è facilmente distribuibile
  • Funziona presupponendo che tutte le app JVM (locali) in esecuzione siano "monitorabili".Sembra che da Java 6 tutte le app sono generalmente (a meno che non si confighi attivamente di fronte)
  • Probabilmente funziona solo per Java 6+
  • Eclipse non pubblica la classe principale, quindi non otterrai Eclipse PID facilmente bug in MonitorEdVMutil?

AGGIORNAMENTO:Ho appena ricontrollato che JPS utilizzi in questo modo, ovvero la libreria Jvmstat (parte di tool.jar).Quindi non è necessario chiamare JPS come processo esterno, chiamare direttamente la libreria Jvmstat come mostra il mio esempio.In questo modo puoi anche ottenere l'elenco di tutte le JVM in esecuzione su localhost.Vedi JPS codice sorgente:

Puoi provare getpid() In JNR-Posix.

Ha un wrapper POSIX di Windows che chiama getpid() da libc.

So che questo è un vecchio thread, ma volevo sottolineare che l'API per ottenere il PID (così come altre manipolazioni del processo Java in fase di esecuzione) viene aggiunta alla classe Process in JDK 9: http://openjdk.java.net/jeps/102

Ho trovato una soluzione che potrebbe essere un po' un caso limite e non l'ho provata su un sistema operativo diverso da Windows 10, ma penso che valga la pena notarlo.

Se ti ritrovi a lavorare con J2V8 e nodejs, puoi eseguire una semplice funzione javascript che ti restituisce il pid del processo Java.

Ecco un esempio:

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

Aggiunta ad altre soluzioni.

con Java 10, per ottenere process id

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

Ecco la mia soluzione:

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

Questo è quello che ho usato quando avevo requisiti simili.Ciò determina correttamente il PID del processo Java.Lascia che il tuo codice Java generi un server su un numero di porta predefinito e quindi esegua i comandi del sistema operativo per scoprire il PID in ascolto sulla porta.Per Linux

netstat -tupln | grep portNumber
Autorizzato sotto: CC-BY-SA insieme a attribuzione
Non affiliato a StackOverflow
scroll top