Bir Java programı kendi işlem kimliğini nasıl alabilir?


Yanıtlar:


322

Tüm jvm uygulamalarında çalışacağı garanti edilebilecek platformdan bağımsız bir yol yoktur. ManagementFactory.getRuntimeMXBean().getName()en iyi (en yakın) çözüm gibi görünüyor. Kısa ve muhtemelen her uygulamada geniş kullanımda çalışıyor.

Linux + pencerelerinde 12345@hostname( 12345işlem kimliği olmak üzere) gibi bir değer döndürür . O olsa dikkat docs göre , bu değeri hakkında hiçbir garanti vardır:

Çalışan Java sanal makinesini temsil eden adı döndürür. Döndürülen ad dizesi herhangi bir isteğe bağlı dize olabilir ve bir Java sanal makine uygulaması, döndürülen ad dizesine platforma özgü yararlı bilgileri katmayı seçebilir. Çalışan her sanal makinenin farklı bir adı olabilir.

Java 9'da yeni işlem API'si kullanılabilir:

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

2
Bu çözüm gerçekten kırılgandır. Aşağıda Hyperic Sigar ile ilgili bir cevap bulabilirsiniz.
Michael Klishin


111

JNA kullanabilirsiniz . Ne yazık ki, mevcut işlem kimliğini almak için henüz ortak bir JNA API'sı yok, ancak her platform oldukça basit:

pencereler

O jna-platform.jarzaman şunlara sahip olduğunuzdan emin olun :

int pid = Kernel32.INSTANCE.GetCurrentProcessId();

Unix

Bildirmek:

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

Sonra:

int pid = CLibrary.INSTANCE.getpid();

Java 9

Java 9 altında, yeni işlem API'si geçerli işlem kimliğini almak için kullanılabilir. Önce geçerli işleme bir tanıtıcı alıp sonra PID'yi sorgulayın:

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

4
+1 Ama güvenlikle kısıtlı bir ortamda (tomcat, WebLogic vb.) Çalışmaması gerektiğinden korkuyorum.
Şubat'ta ATorras

getpid()Çözüm ayrıca "Sistem" kütüphaneye bir JNA çağrısı ile, OS X için çalışır.
Daniel Widdis

Ancak, error: cannot find symboljdk9 için alıyorum
skytree

56

İşte bir arka kapı yöntemidir olabilecek tüm sanal makineler ile çalışmaz ama (hem Linux ve pencereler üzerinde çalışması gerekir burada orijinal örnek ):

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
çok güzel, sadece hem JRockit hem de Hotspot JVM'lerde çalıştığını doğruladı.
Drupad Panchal

1
Güzel bir çözüm. Bu yöntemin (ve sınıftaki diğerlerinin) halka açık ve kolay erişilebilir olmasının iyi bir nedeni olduğunu varsayacağım ve bunun ne olduğunu merak ediyorum.
fragorl

2
Oracle Java ekibi, Java olmayan tüm paketleri (örneğin sun. *) Gizlemeyi planladıklarını açıkladı. Yukarıdaki uygulama ile benzer bir uygulamanız varsa, kodunuzun bozulmaması için bir alternatif bulmak isteyebilirsiniz.
hfontanez

Güneş olarak da benim için çalışmıyor. * Paketler muhtemelen kaldırılmış veya erişilemez (VMManagement bir türe çözümlenemez).
Mike Stoddart

Yansımanın çalışma şekli nedeniyle sun.management. * Erişimine gerek yoktur. Sadece getDeclaredMethodtarafından döndürülen Nesne üzerinde gerçekleştirin jvm.get(runtime).
Andrew T Finnell

36

Sigar'ı deneyin . çok kapsamlı API'lar. Apache 2 lisansı.

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

6
Bunun için SIGAR'ı nasıl kullanacağınızı açıklarsanız çok daha fazla oyunuz olur
Brad Mace

1
Bağlantı koptu. Bunu nasıl kullanacağınıza dair bir örnek verdiniz, ancak bunun için bir bağımlılık var mı?
Jules

github.com/hyperic/sigar kullanılabilir bir konum gibi görünüyor; Bu aynı zamanda Java bağları ile yerel kod olduğunu gösterir, bu da onu birçok bağlam için daha az bir çözüm haline getirebilir.
Zastai

26

Aşağıdaki yöntem PID'yi buradan ayıklamaya çalışır 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;
}

getProcessId("<PID>")Mesela arayın .


6
VisualVM, kendinden PID almak için benzer kodu kullanır, com.sun.tools.visualvm.application.jvm.Jvm # ApplicationSupport # createCurrentApplication () öğesini kontrol edin. Onlar uzmanlar, bu yüzden güvenilir, çapraz platform çözümü gibi görünüyor.
Espinosa

@Espinosa VisualVM yalnızca bir OpenJDK / Oracle / GraalVM JVM üzerinde çalışmayı destekler (2020 itibariyle). Bu, buna göre varsayımlarda bulunabilecekleri anlamına gelir. Bunu yaparsanız, satıcıya bağımlı olursunuz ve örneğin J9 üzerinde çalışıyorsa kodunuz bozulabilir.
Thorbjørn Ravn Andersen

24

Eski JVM için, Linux'ta ...

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
Eğer bunu yapacaksan, yap int pid = Integer.parseInt(new File("/proc/self").getCanonicalFile().getName());. Neden ekstra dönmeler?
David Citron

2
Meraklı için @David'in yorumundaki numara aslında işe yarıyor. Birisi nedenini söyleyebilir mi? getCanonicalFile()PID'ye "kendini" dönüştüren yöntemde bir çeşit sihir mi?
GreenGiant

7
getCanonicalFile () symlink / proc / self / -> / proc / 1234'ü çözer, ls -al / proc / self'i deneyin
Michael

2
@DavidCitron +1! haklısın, getCanonicalFile düşünmedim :-)
ggrandes

18

Projemi kontrol edebilirsiniz: GitHub'da JavaSysMon . İşlem kimliği ve bir dizi başka şey (CPU kullanımı, bellek kullanımı) çapraz platform (şu anda Windows, Mac OSX, Linux ve Solaris) sağlar


Bir İşlemin PID'sini Java ile başlatmak mümkün müdür? Veya bu sorunu çözmek için bir "yolunuzu" İşlem başlat?
Panayotis

17

Java 9'dan beri, bir işlemin yerel kimliğini döndüren bir Process.getPid () yöntemi vardır:

public abstract class Process {

    ...

    public long getPid();
}

Geçerli Java işleminin işlem kimliğini almak için ProcessHandlearabirimi kullanabilirsiniz :

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

2
Java 9'da geçerli çalışan işlem için bir Process örneğinin nasıl alınacağını açıklayabilir misiniz?
Augusto

2016'da Java 9'u kullanmak için harika bir cevap! Javadoc'lara bir bağlantı ekleyebilir misiniz? thanks
crazyGuy

8

Scala'da:

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

Bu, Java 9 piyasaya sürülünceye kadar Unix sistemlerinde bir geçici çözüm sağlayacaktır. (Biliyorum, soru Java ile ilgiliydi, ancak Scala için eşdeğer bir soru olmadığından, bunu aynı soruya rastlayabilecek Scala kullanıcıları için bırakmak istedim.)


7

Bütünlüğü sağlamak için bir ambalaj olup Yay Boot için

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

çözüm. Bir tamsayı gerekiyorsa, bu tek astarlı olarak toplanabilir:

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

Birisi zaten Bahar önyükleme kullanıyorsa, org.springframework.boot.ApplicationPid kullanabilir.

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

ToString () yöntemi, pid veya '???'

ManagementFactory kullanan uyarılar zaten diğer cevaplarda tartışılmıştır.


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

Bulduğum en son linux üzerinde kullanılabilir denilen bir sistem özelliğisun.java.launcher.pid olmasıdır. Planım bunu kullanmak ve eğer bulamazsa kullanmaktır JMX bean.


Ubuntu 16.04 ve Java 8 ile durumumda null döndürür
david.perez

4

Bu bilgiyi nereden aradığınıza bağlıdır.

Konsoldan bilgi arıyorsanız jps komutunu kullanabilirsiniz. Komut, Unix ps komutuna benzer çıktılar verir ve inanıyorum çünkü JDK ile birlikte gelir

Eğer süreçten bakıyorsanız (Wouter Coekaerts tarafından söylendiği gibi) RuntimeMXBean muhtemelen en iyi seçimdir. Sun JDK 1.6 u7 kullanan Windows'ta getName () 'den çıktı [PROCESS_ID] @ [MACHINE_NAME] biçimindedir. Ancak jps yürütmeyi deneyebilir ve sonucu bundan ayrıştırabilirsiniz:

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

Hiçbir seçenek olmadan çalıştırılırsa, çıktı işlem kimliği ve ardından ad olmalıdır.


1
JPS aracı, tools.jar dosyasının bir parçası olan jvmstat kütüphanesini kullanır. Örneğimi kontrol edin veya JPS kaynak koduna bakın: grepcode.com/file_/repository.grepcode.com/java/root/jdk/… . Harici işlem olarak JPS'yi çağırmaya gerek yoktur, doğrudan jvmstat kütüphanesini kullanın.
Espinosa

4

Bu JConsole kodu ve potansiyel olarak jps ve VisualVM kullanır. sun.jvmstat.monitor.*Paketten sınıftan yararlanır 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;
    }
}

Birkaç yakalama var:

  • tool.jarOracle JDK ancak JRE ile dağıtılan bir kütüphane!
  • tool.jarMaven deposundan alamazsınız ; Maven ile yapılandırmak biraz zor
  • tool.jarKolayca dağıtılabilir değildir bu yüzden muhtemelen platformu bağımlı (native?) Kodu içeren
  • JVM uygulamalarını çalıştıran tüm (yerel) uygulamaların "izlenebilir" olduğu varsayımı altındadır. Java 6'dan tüm uygulamaların genellikle olduğu görülüyor (aktif olarak tersini yapılandırmadıkça)
  • Muhtemelen sadece Java 6+ için çalışır
  • Eclipse ana sınıfı yayınlamaz, bu yüzden kolayca Eclipse PID kolayca MonitoredVmUtil hata elde edemezsiniz?

GÜNCELLEME: Sadece JPS bu şekilde kullandığını, Jvmstat kütüphanesi (tool.jar parçası) olduğunu çift kontrol ettim. Bu yüzden JPS'yi harici işlem olarak çağırmanıza gerek yok, örneğimin gösterdiği gibi doğrudan Jvmstat kütüphanesini arayın. Bu şekilde localhost üzerinde çalıştırılan tüm JVM'lerin listesini de alabilirsiniz. JPS kaynak koduna bakın :


mainClass.getName () çalışmazsa mainClass.getCanonicalName () öğesini kullanmayı deneyin;
Narendra Parmar

3

Bunu diğer çözümlere ekliyorum.

Java 10 ile process id

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


1

Deneyebilirsin getpid()içinde JNR-Posix .

Getpid () öğesini libc'den çağıran bir Windows POSIX sarmalayıcısı vardır.



1

Biraz uç durumda olabilecek bir çözüm buldum ve Windows 10'dan başka bir işletim sisteminde denemedim, ancak fark etmeye değer.

Kendinizi J2V8 ve nodejs ile çalışırken bulursanız, size java işleminin pidini döndüren basit bir javascript işlevi çalıştırabilirsiniz.

İşte bir örnek:

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

İşte benim çözümüm:

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

Bu,
pid'in

Kodumu güncelleyebilmem için doğru çözüm nedir?
PartialData

-6

Benzer bir gereksinimim olduğunda kullandığım bu oldu. Bu, Java işleminin PID'sini doğru olarak belirler. Java kodunuzun önceden tanımlanmış bir bağlantı noktası numarasında bir sunucu oluşturmasına izin verin ve ardından bağlantı noktasında dinleme yapan PID'yi bulmak için OS komutlarını yürütün. Linux için

netstat -tupln | grep portNumber

3
Kabuk komut dosyaları arıyorsanız, yukarıdaki gibi daha basit bir şey bash -c 'echo $PPID'veya / proc yanıtları da yapabilirsiniz
Zengin
Sitemizi kullandığınızda şunları okuyup anladığınızı kabul etmiş olursunuz: Çerez Politikası ve Gizlilik Politikası.
Licensed under cc by-sa 3.0 with attribution required.