एक जावा प्रोग्राम अपनी प्रक्रिया आईडी कैसे प्राप्त कर सकता है?


341

मैं अपने जावा प्रोसेस की आईडी कैसे प्राप्त करूं?

मुझे पता है कि कई प्लेटफ़ॉर्म-निर्भर हैक हैं, लेकिन मैं अधिक सामान्य समाधान पसंद करूंगा।



4
यह JDK9 में तय किया गया है। openjdk.java.net/jeps/102
एंड्रयू

जवाबों:


322

कोई भी प्लेटफ़ॉर्म-स्वतंत्र तरीका मौजूद नहीं है जिसे सभी jvm कार्यान्वयन में काम करने की गारंटी दी जा सकती है। ManagementFactory.getRuntimeMXBean().getName()सबसे अच्छा (निकटतम) समाधान जैसा दिखता है। यह छोटा है, और शायद व्यापक रूप से हर कार्यान्वयन में काम करता है।

Linux + windows पर यह एक मान देता है जैसे 12345@hostname( 12345प्रोसेस आईडी होना)। हालांकि , डॉक्स के अनुसार , इस मान के बारे में कोई गारंटी नहीं है:

चल रहे जावा वर्चुअल मशीन का प्रतिनिधित्व करने वाला नाम लौटाता है। लौटा हुआ नाम स्ट्रिंग किसी भी मनमाने ढंग से स्ट्रिंग हो सकता है और जावा वर्चुअल मशीन कार्यान्वयन लौटे नाम स्ट्रिंग में प्लेटफ़ॉर्म-विशिष्ट उपयोगी जानकारी एम्बेड करने का विकल्प चुन सकता है। प्रत्येक चलने वाली वर्चुअल मशीन का एक अलग नाम हो सकता है।

जावा 9 में नई प्रक्रिया एपीआई का उपयोग किया जा सकता है:

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

2
यह समाधान वास्तव में नाजुक है। नीचे हाइपरिक सिगार के बारे में एक उत्तर देखें।
माइकल केलिसिन


111

आप JNA का उपयोग कर सकते हैं । दुर्भाग्य से वर्तमान प्रक्रिया आईडी प्राप्त करने के लिए कोई सामान्य JNA API नहीं है, लेकिन प्रत्येक प्लेटफ़ॉर्म बहुत सरल है:

खिड़कियाँ

सुनिश्चित करें कि आपके पास jna-platform.jarतब:

int pid = Kernel32.INSTANCE.GetCurrentProcessId();

यूनिक्स

घोषित:

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

फिर:

int pid = CLibrary.INSTANCE.getpid();

जावा ९

जावा 9 के तहत वर्तमान प्रक्रिया आईडी प्राप्त करने के लिए नई प्रक्रिया एपीआई का उपयोग किया जा सकता है। पहले आप वर्तमान प्रक्रिया को हैंडल करते हैं, फिर PID को क्वेरी करते हैं:

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

4
+1 लेकिन मुझे डर है कि सुरक्षा के अभाव वाले वातावरण में यह काम नहीं करना चाहिए (टॉमकैट, वेबलॉगिक, आदि)।
अतिशयोक्ति

getpid()समाधान भी ओएस एक्स के लिए काम करता है, "सिस्टम" पुस्तकालय के लिए एक JNA कॉल के साथ।
डैनियल विदिस

हालाँकि, मैं error: cannot find symboljdk9 के लिए मिलता हूं
skytree

56

यहाँ एक पिछले दरवाजे की विधि है जो सभी वीएम के साथ काम नहीं कर सकती है लेकिन यह लिनक्स और विंडोज़ ( मूल उदाहरण ) दोनों पर काम करना चाहिए :

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
बहुत अच्छा है, बस सत्यापित करें कि यह JRockit और हॉटस्पॉट JVM दोनों पर काम करता है।
द्रुपद पंचाल

1
अच्छा काम है। मैं मानने जा रहा हूं कि एक अच्छा कारण है कि यह विधि (और कक्षा में अन्य) सार्वजनिक और आसानी से सुलभ नहीं हैं, और मैं यह जानने के लिए उत्सुक हूं कि यह क्या है।
सुगंध

2
ओरेकल जावा टीम ने घोषणा की है कि वे सभी गैर-जावा पैकेज (यानी सूर्य। *) को छिपाने का इरादा रखते हैं, मेरा मानना ​​है कि जावा 10 (2018 के लिए निर्धारित - शायद जावा 9) से शुरू होगा। यदि आपके पास उपरोक्त के समान कार्यान्वयन है, तो आप एक विकल्प का पता लगाना चाह सकते हैं ताकि आपका कोड न टूटे।
hfontanez

मेरे लिए सूरज के रूप में भी काम नहीं करता है। * पैकेज शायद निकाले जाते हैं या दुर्गम होते हैं (VMManagement को एक प्रकार से हल नहीं किया जा सकता है)।
माइक स्टोडर्ट

जिस तरह से परावर्तन कार्य करता है, उसके कारण sun.management तक पहुँच है। * की आवश्यकता नहीं है। बस द्वारा दिए getDeclaredMethodगए ऑब्जेक्ट पर प्रदर्शन करें jvm.get(runtime)
एंड्रयू टी फिनेल

36

सिगार का प्रयास करें । बहुत व्यापक एपीआई। अपाचे 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();
}

6
यदि आपके पास इसके लिए SIGAR का उपयोग करने का तरीका बताया जाए तो आपके पास बहुत अधिक उत्थान होगा
ब्रैड मेस

1
लिंक टूट गया है। आप इसका उपयोग कैसे करें, इसका एक उदाहरण देते हैं, लेकिन क्या इसके लिए मावेन निर्भरता है?
जूल्स

github.com/hyperic/sigar एक उपयोगी स्थान प्रतीत होता है; इससे यह भी पता चलता है कि यह जावा बाइंडिंग के साथ मूल कोड है, जो इसे कई संदर्भों के समाधान से कम कर सकता है।
ज़स्तई

26

निम्न विधि PID को निकालने का प्रयास करती है 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>")उदाहरण के लिए, बस कॉल करें ।


6
VisualVM स्वयं पीआईडी ​​पाने के लिए इसी तरह के कोड का उपयोग करता है, com.sun.tools.visualvm.application.jvm.Jvm # ApplicationSupport # createCurrentApplication () चेक करें। वे विशेषज्ञ हैं, इसलिए यह भरोसेमंद, क्रॉस प्लेटफॉर्म समाधान की तरह दिखता है।
एस्पिनोसा

@Espinosa VisualVM केवल OpenJDK / Oracle / GraalVM JVM (2020 तक) पर चलने का समर्थन करता है। इसका मतलब है कि वे तदनुसार धारणा बना सकते हैं। यदि आप भी ऐसा ही करते हैं, तो आप विक्रेता पर निर्भर हो जाते हैं और उदाहरण के लिए J9 पर चलने पर आपका कोड टूट सकता है।
Thorbjørn Ravn Andersen

24

पुराने JVM के लिए, 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";
}

52
यदि आप ऐसा करने जा रहे हैं, तो बस करें int pid = Integer.parseInt(new File("/proc/self").getCanonicalFile().getName());। क्यों अतिरिक्त gyrations?
डेविड सिट्रॉन

2
जिज्ञासु के लिए, @ डेविड की टिप्पणी में चाल वास्तव में काम करती है। क्या कोई कह सकता है क्यों? किसी प्रकार का जादू getCanonicalFile()जो "स्वयं" को पीआईडी ​​में परिवर्तित करता है?
ग्रीनजाइंट

7
getCanonicalFile () सिमलिंक / proc / self / -> / proc / 1234 को हल करता है, ls -al / proc / self को आज़माएं
Michael

2
@DavidCitron +1! आप सही हैं, मैंने नहीं सोचा कि getCanonicalFile :-)
ggrandes

18

आप मेरे प्रोजेक्ट को देख सकते हैं: GitHub पर JavaSysMon । यह प्रक्रिया आईडी और अन्य सामान का एक गुच्छा (सीपीयू उपयोग, मेमोरी उपयोग) क्रॉस-प्लेटफॉर्म (वर्तमान में विंडोज, मैक ओएसएक्स, लिनक्स और सोलारिस) प्रदान करता है


क्या जावा द्वारा शुरू की गई प्रक्रिया की पीआईडी ​​प्राप्त करना संभव है? या इस समस्या को ठीक करने के लिए एक प्रक्रिया "अपना रास्ता" शुरू करें?
पनायोटिस

17

Java 9 के बाद से एक मेथड Process.getPid () है जो किसी प्रक्रिया की मूल आईडी लौटाता है:

public abstract class Process {

    ...

    public long getPid();
}

वर्तमान जावा प्रक्रिया की प्रक्रिया आईडी प्राप्त करने के लिए कोई ProcessHandleइंटरफ़ेस का उपयोग कर सकता है:

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

2
क्या आप बता सकते हैं कि जावा 9 में वर्तमान चल रही प्रक्रिया के लिए एक प्रक्रिया उदाहरण कैसे प्राप्त करें?
अगस्तो

2016 में जावा 9 का उपयोग करने के लिए शानदार जवाब! क्या आप javadocs का लिंक जोड़ सकते हैं? धन्यवाद
crazyGuy

8

स्काला में:

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

यह आपको यूनिक्स सिस्टम पर एक वर्कअराउंड देना चाहिए जब तक कि जावा 9 जारी नहीं किया जाएगा। (मुझे पता है, सवाल जावा के बारे में था, लेकिन चूंकि स्काला के लिए कोई समकक्ष प्रश्न नहीं है, इसलिए मैं इसे स्काला उपयोगकर्ताओं के लिए छोड़ना चाहता था जो एक ही प्रश्न में ठोकर खा सकते हैं।)


7

पूर्णता के लिए वहाँ में एक आवरण है वसंत बूट के लिए

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

समाधान। यदि एक पूर्णांक की आवश्यकता होती है, तो इसे एक-लाइनर तक सम्‍मिलित किया जा सकता है:

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

यदि कोई पहले से ही स्प्रिंग बूट का उपयोग करता है, तो वह org.springframework.boot.ApplicationPid का उपयोग कर सकता है

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

TheString () विधि pid या '???' को प्रिंट करती है।

ManagementFactory का उपयोग करने वाले कैविट्स अन्य उत्तरों में पहले से ही चर्चा कर रहे हैं।



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

नवीनतम मैंने पाया है कि एक प्रणाली गुण है जिसे कहा जाता है sun.java.launcher.pidजो कम से कम लिनक्स पर उपलब्ध है। मेरी योजना का उपयोग करना है और यदि इसका उपयोग नहीं किया जाता है JMX bean


उबंटू 16.04 और जावा 8 के साथ मेरे मामले में, यह अशक्त है
david.perez

4

यह इस बात पर निर्भर करता है कि आप कहां से जानकारी की तलाश कर रहे हैं।

यदि आप कंसोल से जानकारी ढूंढ रहे हैं तो आप jps कमांड का उपयोग कर सकते हैं। कमांड यूनिक्स पीएस कमांड के समान आउटपुट देता है और जेडडीके के साथ आता है क्योंकि मैं 1.5 मानता हूं

यदि आप RuntimeMXBean (Wouter Coekaerts द्वारा कहा गया है) प्रक्रिया से देख रहे हैं, तो शायद यह आपका सबसे अच्छा विकल्प है। Sun JDK 1.6 u7 का उपयोग कर विंडोज पर getName () से आउटपुट फॉर्म [PROCESS_ID] @ [MACHINE_NAME] के रूप में है। हालाँकि आप jps को अंजाम देने की कोशिश कर सकते हैं और उससे परिणाम को पार कर सकते हैं:

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

यदि कोई विकल्प नहीं है तो आउटपुट को नाम के बाद प्रोसेस आईडी होना चाहिए।


1
JPS टूल jvmstat पुस्तकालय, tools.jar का हिस्सा उपयोग करता है। मेरा उदाहरण देखें या JPS स्रोत कोड देखें: grepcode.com/file_/repository.grepcode.com/java/root/jdk/… । JPS को बाहरी प्रक्रिया के रूप में कॉल करने की आवश्यकता नहीं है, सीधे jvmstat लाइब्रेरी का उपयोग करें।
एस्पिनोसा

4

यह कोड JConsole, और संभावित jps और VisualVM का उपयोग करता है। यह sun.jvmstat.monitor.*संकुल से, से कक्षाओं का उपयोग करता है 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;
    }
}

कुछ कैच हैं:

  • tool.jarएक पुस्तकालय ओरेकल JDK नहीं बल्कि JRE के साथ वितरित है!
  • आप tool.jarमावेन रेपो से नहीं मिल सकते ; मावेन के साथ इसे कॉन्फ़िगर करना थोड़ा मुश्किल है
  • tool.jarशायद मंच निर्भर (देशी?) कोड शामिल तो यह आसानी से वितरण योग्य नहीं है
  • यह इस धारणा के तहत चलता है कि JVM ऐप चलाने वाले सभी (स्थानीय) "मॉनिटरेबल" हैं। ऐसा लगता है कि जावा 6 से सभी एप्लिकेशन आम तौर पर हैं (जब तक आप सक्रिय रूप से विपरीत कॉन्फ़िगर नहीं करते हैं)
  • यह शायद केवल जावा 6+ के लिए काम करता है
  • ग्रहण मुख्य वर्ग को प्रकाशित नहीं करता है, इसलिए आपको मॉनिटर किए गए VVUtil में आसानी से ग्रहण PID नहीं मिलेगा?

अद्यतन: मैंने अभी-अभी डबल चेक किया है कि JPS इस तरह से उपयोग करता है, वह है Jvmstat पुस्तकालय (tool.jar का हिस्सा)। इसलिए जेपीएस को बाहरी प्रक्रिया के रूप में कॉल करने की आवश्यकता नहीं है, मेरे उदाहरण के रूप में सीधे Jvmstat पुस्तकालय को कॉल करें। आप इस तरह से लोकलहोस्ट पर सभी JVM रनरिन की सूची प्राप्त कर सकते हैं। जेपीएस स्रोत कोड देखें :


अगर mainClass.getName () काम नहीं करता है तो mainClass.getCanonicalName () का उपयोग करने का प्रयास न करें;
नरेंद्र परमार

3

मैं इसे अन्य समाधानों में जोड़ रहा हूं।

जावा 10 के साथ, पाने के लिए process id

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

2

अपाचे 2.0 के लाइसेंस के बारे में अश्विन जयप्रकाश के जवाब (+1) के आधार पर SIGAR, यहां बताया गया है कि मैं इसका इस्तेमाल मौजूदा प्रक्रिया के केवल पीआईडी ​​पाने के लिए कैसे कर सकता हूं:

import org.hyperic.sigar.Sigar;

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

भले ही यह सभी प्लेटफार्मों पर काम नहीं करता है, यह यहां सूचीबद्ध के रूप में लिनक्स, विंडोज, ओएस एक्स और विभिन्न यूनिक्स प्लेटफार्मों पर काम करता है


1

आप JNR-Posixgetpid() में कोशिश कर सकते हैं ।

इसमें एक Windows POSIX रैपर है जो कि libp से getpid () को कॉल करता है।


1

मुझे पता है कि यह एक पुराना धागा है, लेकिन मैं पीआईडी ​​पाने के लिए उस एपीआई को कॉल करना चाहता था (साथ ही रनटाइम में जावा प्रक्रिया के अन्य हेरफेर) को जेडीके 9: http: // openjdk में प्रोसेस क्लास में जोड़ा जा रहा है । java.net/jeps/102


9
वाह, यह तेज़ था। इसमें केवल सात साल लगे! She
दिमित्री शेट्टमैन

1

मुझे एक समाधान मिला जो एक किनारे का मामला हो सकता है और मैंने इसे विंडोज़ 10 के अलावा अन्य ओएस पर नहीं आज़माया था, लेकिन मुझे लगता है कि यह ध्यान देने योग्य है।

यदि आप अपने आप को काम के साथ पाते हैं J2V8 और नोडज के हुए पाते हैं, तो आप एक साधारण जावास्क्रिप्ट फंक्शन चला सकते हैं, जो आपको जावा प्रक्रिया के लिए वापस लौटा देगा।

यहाँ एक उदाहरण है:

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

यहाँ मेरा समाधान है:

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

यह जाँच नहीं करता है कि पीआईडी ​​उपयोग में है या नहीं, लेकिन यदि पीआईडी ​​वर्तमान प्रक्रिया के बराबर है
c0der

सही समाधान क्या है ताकि मैं अपना कोड अपडेट कर सकूं?
PartialData

-6

यह वही है जो मैंने उपयोग किया था जब मुझे इसी तरह की आवश्यकता थी। यह जावा प्रक्रिया के पीआईडी ​​को सही ढंग से निर्धारित करता है। अपने जावा कोड को पूर्व-परिभाषित पोर्ट नंबर पर एक सर्वर को स्पॉन करें और फिर पोर्ट पर सुन रहे पीआईडी ​​का पता लगाने के लिए ओएस कमांड निष्पादित करें। लिनक्स के लिए

netstat -tupln | grep portNumber

3
यदि आप शेल स्क्रिप्ट्स को कॉल कर रहे हैं, तो आप कुछ सरल भी कर सकते हैं जैसे bash -c 'echo $PPID'/ या उत्तर के ऊपर खरीद
रिच
हमारी साइट का प्रयोग करके, आप स्वीकार करते हैं कि आपने हमारी Cookie Policy और निजता नीति को पढ़ और समझा लिया है।
Licensed under cc by-sa 3.0 with attribution required.