Java 프로그램은 어떻게 자체 프로세스 ID를 얻을 수 있습니까?


341

Java 프로세스의 ID를 어떻게 얻습니까?

나는 플랫폼에 의존하는 여러 해킹이 있다는 것을 알고 있지만 더 일반적인 솔루션을 선호합니다.



4
이것은 JDK9에서 수정되어야합니다. openjdk.java.net/jeps/102
Andrew

답변:


322

모든 jvm 구현에서 작동하도록 보장 할 수있는 플랫폼 독립적 인 방법은 없습니다. ManagementFactory.getRuntimeMXBean().getName()최고의 (가장 가까운) 솔루션처럼 보입니다. 짧고 아마도 모든 구현에서 널리 사용됩니다.

linux + windows에서는 12345@hostname( 12345프로세스 ID) 와 같은 값을 반환합니다 . 있다고하더라도 조심 워드 프로세서에 따르면 ,이 값에 대한 보장이 없습니다 :

실행중인 Java 가상 머신을 나타내는 이름을 리턴합니다. 리턴 된 이름 문자열은 임의의 문자열 일 수 있으며 Java 가상 머신 구현은 플랫폼 별 유용한 정보를 리턴 된 이름 문자열에 임베드하도록 선택할 수 있습니다. 실행중인 각 가상 머신의 이름이 다를 수 있습니다.

Java 9 에서는 새로운 프로세스 API를 사용할 수 있습니다.

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

2
이 솔루션은 실제로 취약합니다. 아래 Hyperic Sigar에 대한 답변을 참조하십시오.
Michael Klishin

PID는 잠금 파일에 쓰기 좋은 것을 stackoverflow.com/a/9020391/1422630는
물병 전원

111

JNA를 사용할 수 있습니다 . 불행히도 현재 프로세스 ID를 얻는 일반적인 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

Java 9에서는 새 프로세스 API 를 사용하여 현재 프로세스 ID를 얻을 수 있습니다. 먼저 현재 프로세스에 대한 핸들을 잡고 PID를 쿼리하십시오.

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

4
+1 그러나 보안이 제한된 환경에서는 작동하지 않아야합니다 (tomcat, WebLogic 등).
ATorras

getpid()솔루션은 또한 "System"라이브러리에 대한 JNA 호출과 함께 OS X에서도 작동합니다.
Daniel Widdis

그러나, 나는 얻을 error: cannot find symboljdk9 위해
스카이 트리

56

다음 은 모든 VM에서 작동하지 않을 있지만 Linux 및 Windows 모두에서 작동해야하는 백도어 방법입니다 ( 원본 예제 here ).

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과 Hotspot JVM 모두에서 작동하는지 확인했습니다.
Drupad Panchal

1
좋은 해결 방법. 이 방법 (및 클래스의 다른 방법)이 공개되어 쉽게 액세스 할 수없는 좋은 이유가 있다고 가정하고 그 방법이 무엇인지 궁금합니다.
fragorl

2
Oracle Java 팀은 ​​Java 10이 아닌 모든 패키지 (예 : sun. *)를 숨기겠다고 발표했습니다 (2018 년 예정-아마도 Java 9). 위와 비슷한 구현이 있다면 코드가 깨지지 않도록 대안을 찾아야 할 수 있습니다.
hfontanez

sun. * 패키지가 제거되었거나 액세스 할 수 없을 때 (VMManagement를 유형으로 해석 할 수 없음) 나에게 적합하지 않습니다.
Mike Stoddart

리플렉션 작동 방식으로 인해 sun.management. *에 액세스 할 필요가 없습니다. 에 getDeclaredMethod의해 반환 된 Object를 수행하십시오 jvm.get(runtime).
앤드류 T 핀넬

36

시가를 보십시오 . 매우 광범위한 API. 아파치 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를 사용 하는 방법 을 설명하면 더 많은 지지를 얻을 수 있습니다.
Brad Mace

1
링크가 끊어졌습니다. 이것을 사용하는 방법에 대한 예제를 제공하지만 그것에 대한 의존성이 있습니까?
Jules

github.com/hyperic/sigar 는 유용한 위치 인 것 같습니다. 이것은 또한 Java 바인딩을 사용하는 원시 코드이므로 많은 컨텍스트에서 솔루션을 덜 만들 수 있음을 보여줍니다.
Zastai

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은 유사한 코드를 사용하여 자체 PID를 가져옵니다. com.sun.tools.visualvm.application.jvm.Jvm # ApplicationSupport # createCurrentApplication ()을 확인하십시오. 이들은 전문가이므로 신뢰할 수있는 크로스 플랫폼 솔루션처럼 보입니다.
Espinosa

@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?
David Citron

2
궁금한 점은 @David의 의견에 실제로 적용됩니다. 누군가 이유를 말할 수 있습니까? getCanonicalFile()"self"를 PID로 변환 하는 방법의 일종의 마술 ?
GreenGiant

7
getCanonicalFile ()은 심볼릭 링크 / proc / self /-> / proc / 1234를 해결하고 ls -al / proc / self를 시도하십시오
Michael

2
@DavidCitron +1! 당신이 맞아, getCanonicalFile에서 생각하지 않았다 :-)
ggrandes

18

내 프로젝트를 확인할 수 있습니다 : GitHub의 JavaSysMon . 프로세스 ID와 다른 플랫폼 (CPU 사용량, 메모리 사용량) 크로스 플랫폼 (현재 Windows, Mac OSX, Linux 및 Solaris)을 제공합니다.


Java로 시작한 프로세스의 PID를 얻을 수 있습니까? 아니면이 방법으로 프로세스를 시작하여이 문제를 해결 하시겠습니까?
Panayotis

17

Java 9부터 프로세스의 고유 ID를 리턴하는 Process.getPid () 메소드가 있습니다.

public abstract class Process {

    ...

    public long getPid();
}

현재 Java 프로세스의 프로세스 ID를 얻으려면 ProcessHandle인터페이스를 사용할 수 있습니다 .

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

2
Java 9에서 현재 실행중인 프로세스의 Process 인스턴스를 얻는 방법을 설명 할 수 있습니까?
Augusto

2016 년 Java 9를 사용하는 것에 대한 훌륭한 답변! javadoc에 대한 링크를 추가 할 수 있습니까? 감사합니다
crazyGuy

8

스칼라에서 :

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

이것은 Java 9가 출시 될 때까지 Unix 시스템에 대한 해결 방법을 제공해야합니다. (질문은 Java에 관한 것이지만 Scala에 대한 동등한 질문이 없으므로 동일한 질문에 걸려 넘어 질 수있는 Scala 사용자를 위해 이것을 남기고 싶었습니다.)


7

완전성을 위해 Spring Boot 에는 래퍼가 있습니다 .

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

해결책. 정수가 필요한 경우 1- 라이너로 요약 할 수 있습니다.

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

누군가 이미 Spring Boot를 사용하고 있다면 org.springframework.boot.ApplicationPid를 사용할 수 있습니다.

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

toString () 메소드는 pid 또는 '???'를 인쇄합니다.

ManagementFactory를 사용하는주의 사항은 이미 다른 답변에서 논의되었습니다.


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

내가 찾은 최신이 있다는 것입니다 시스템 프로퍼티 라는 sun.java.launcher.pid리눅스에 적어도 사용할 수 있습니다. 내 계획은 그것을 사용하는 것이며 그것을 사용하지 않는 경우 JMX bean.


우분투 16.04 및 Java 8 나의 경우, null을 반환
david.perez

4

정보를 찾는 위치에 따라 다릅니다.

콘솔에서 정보를 찾고 있다면 jps 명령을 사용할 수 있습니다. 이 명령은 Unix ps 명령과 비슷한 출력을 제공하며 1.5를 믿기 때문에 JDK와 함께 제공됩니다.

프로세스에서 찾고 있다면 RuntimeMXBean (Wouter Coekaerts가 말한 것처럼)이 최선의 선택 일 것입니다. Sun JDK 1.6 u7을 사용하는 Windows에서 getName ()의 출력은 [PROCESS_ID] @ [MACHINE_NAME] 형식입니다. 그러나 jps를 실행하고 그 결과를 구문 분석 할 수 있습니다.

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

옵션없이 실행하면 출력은 프로세스 ID 다음에 이름이어야합니다.


1
JPS 도구는 tools.jar의 일부인 jvmstat 라이브러리를 사용합니다. 내 예제를 확인하거나 JPS 소스 코드 : grepcode.com/file_/repository.grepcode.com/java/root/jdk/…를 참조하십시오 . 외부 프로세스로 JPS를 호출 할 필요가 없습니다. jvmstat 라이브러리를 직접 사용하십시오.
Espinosa

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.jarMaven 저장소에서 얻을 수는 없습니다 . Maven으로 구성하는 것은 약간 까다 롭습니다.
  • tool.jar쉽게 배포되지 않도록 아마도 플랫폼에 의존 (기본?) 코드를 포함
  • 실행되는 모든 (로컬) JVM 앱이 "모니터링 가능"하다고 가정합니다. Java 6부터 모든 앱이 일반적으로 보입니다 (대 향적으로 적극적으로 구성하지 않는 한)
  • 아마 Java 6 이상에서만 작동합니다.
  • Eclipse는 메인 클래스를 게시하지 않으므로 MonitoredVmUtil에서 Eclipse PID를 쉽게 얻지 못합니까?

업데이트 : JPS 가이 방법을 사용하는지, 즉 Jvmstat 라이브러리 (tool.jar의 일부)를 두 번 확인했습니다. 따라서 외부 프로세스로 JPS를 호출 할 필요가 없습니다. 예제에 표시된대로 Jvmstat 라이브러리를 직접 호출하십시오. 이 방법으로 localhost에서 실행되는 모든 JVM 목록을 얻을 수 있습니다. JPS 소스 코드를 참조하십시오 .


mainClass.getName ()이 작동하지 않으면 mainClass.getCanonicalName ()을 사용하십시오.
Narendra Parmar

3

이것을 다른 솔루션에 추가하고 있습니다.

Java 10으로 process id

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


1

JNR-Posixgetpid() 에서 시도해 볼 수 있습니다 .

libc에서 getpid ()를 호출하는 Windows POSIX 랩퍼가 있습니다.



1

약간의 경우가 될 수있는 솔루션을 발견했으며 Windows 10 이외의 다른 OS에서는 시도하지 않았지만 주목할 가치가 있다고 생각합니다.

J2V8 및 nodejs로 작업하는 것을 발견 하면 간단한 자바 스크립트 함수를 실행하여 Java 프로세스의 pid를 반환 할 수 있습니다.

예를 들면 다음과 같습니다.

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

이것은 pid가 사용 중인지 확인하지 않지만, pid가 현재 프로세스 pid와 동일한 경우
c0der

코드를 업데이트 할 수있는 올바른 해결책은 무엇입니까?
PartialData

-6

이것은 비슷한 요구 사항이 있었을 때 사용한 것입니다. Java 프로세스의 PID를 올바르게 결정합니다. Java 코드가 사전 정의 된 포트 번호로 서버를 생성 한 다음 OS 명령을 실행하여 포트에서 PID 수신을 찾으십시오. 리눅스

netstat -tupln | grep portNumber

3
쉘 스크립트를 호출하는 경우 위와 같은 간단한 bash -c 'echo $PPID'/ proc 답변을 사용할 수도 있습니다.
Rich
당사 사이트를 사용함과 동시에 당사의 쿠키 정책개인정보 보호정책을 읽고 이해하였음을 인정하는 것으로 간주합니다.
Licensed under cc by-sa 3.0 with attribution required.