Come posso ottenere l'ID del mio processo Java?
So che esistono diversi hack dipendenti dalla piattaforma, ma preferirei una soluzione più generica.
Come posso ottenere l'ID del mio processo Java?
So che esistono diversi hack dipendenti dalla piattaforma, ma preferirei una soluzione più generica.
Risposte:
Non esiste un modo indipendente dalla piattaforma che può essere garantito per funzionare in tutte le implementazioni jvm.
ManagementFactory.getRuntimeMXBean().getName()
sembra la migliore soluzione (più vicina). È breve e probabilmente funziona in tutte le implementazioni in largo uso.
Su linux + windows restituisce un valore simile 12345@hostname
( 12345
essendo l'id del processo). Attenzione però che secondo i documenti non ci sono garanzie su questo valore:
Restituisce il nome che rappresenta la macchina virtuale Java in esecuzione. La stringa del nome restituita può essere qualsiasi stringa arbitraria e un'implementazione della macchina virtuale Java può scegliere di incorporare informazioni utili specifiche della piattaforma nella stringa del nome restituito. Ogni macchina virtuale in esecuzione potrebbe avere un nome diverso.
In Java 9 è possibile utilizzare la nuova API di processo :
long pid = ProcessHandle.current().pid();
Potresti usare JNA . Sfortunatamente non esiste ancora un'API JNA comune per ottenere l'ID processo corrente, ma ogni piattaforma è piuttosto semplice:
Assicurati di avere jna-platform.jar
quindi:
int pid = Kernel32.INSTANCE.GetCurrentProcessId();
Dichiarare:
private interface CLibrary extends Library {
CLibrary INSTANCE = (CLibrary) Native.loadLibrary("c", CLibrary.class);
int getpid ();
}
Poi:
int pid = CLibrary.INSTANCE.getpid();
In Java 9 è possibile utilizzare la nuova API di processo per ottenere l'ID processo corrente. Innanzitutto prendi un handle per il processo corrente, quindi esegui una query sul PID:
long pid = ProcessHandle.current().pid();
getpid()
soluzione funziona anche per OS X, con una chiamata JNA alla libreria "Sistema".
error: cannot find symbol
per jdk9
Ecco un metodo backdoor che potrebbe non funzionare 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);
getDeclaredMethod
l'oggetto restituito da jvm.get(runtime)
.
Prova Sigar . API molto estese. Licenza 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();
}
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;
}
Basta chiamare getProcessId("<PID>")
, per esempio.
Per 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";
}
int pid = Integer.parseInt(new File("/proc/self").getCanonicalFile().getName());
. Perché le giravolte extra?
getCanonicalFile()
metodo che converte "sé" in PID?
Puoi dare un'occhiata al mio progetto: JavaSysMon su GitHub. Fornisce ID di processo e un sacco di altre cose (utilizzo della CPU, utilizzo della memoria) multipiattaforma (attualmente Windows, Mac OSX, Linux e Solaris)
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 di processo del processo Java corrente, è possibile utilizzare l' ProcessHandle
interfaccia:
System.out.println(ProcessHandle.current().pid());
Alla 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 c'è un wrapper in Spring Boot 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 utilizza già l'avvio di Spring, potrebbe usare org.springframework.boot.ApplicationPid
ApplicationPid pid = new ApplicationPid();
pid.toString();
Il metodo toString () stampa il pid o '???'.
Gli avvertimenti che utilizzano ManagementFactory sono già discussi in altre risposte.
L'ultima che ho trovato è che esiste una proprietà di sistema chiamata sun.java.launcher.pid
che è disponibile almeno su Linux. Il mio piano è quello di usarlo e se non si trova ad usare il JMX bean
.
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 ps Unix e viene fornito con il JDK poiché credo 1.5
Se stai osservando 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.
Questo è il codice JConsole e potenzialmente utilizza jps e VisualVM. Utilizza le classi dal
sun.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 alcune catture:
tool.jar
è una libreria distribuita con Oracle JDK ma non JRE!tool.jar
dal repository Maven; configurarlo con Maven è un po 'complicatotool.jar
probabilmente contiene codice dipendente dalla piattaforma (nativo?) Quindi non è facilmente distribuibileAGGIORNAMENTO: Ho appena verificato che JPS usi 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. Puoi anche ottenere l'elenco di tutte le JVM che girano su localhost in questo modo. Vedi codice sorgente JPS :
Sto aggiungendo questo, ad altre soluzioni.
process id
final RuntimeMXBean runtime = ManagementFactory.getRuntimeMXBean();
final long pid = runtime.getPid();
out.println("Process ID is '" + pid);
Sulla base della risposta di Ashwin Jayaprakash (+1) sulla licenza di Apache 2.0 SIGAR
, ecco come lo uso 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 .
So che questo è un vecchio thread, ma volevo chiamare 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 notare.
Se ti trovi 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();
}
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 esegui i comandi del sistema operativo per scoprire l'ascolto PID sulla porta. Per Linux
netstat -tupln | grep portNumber