Javaプログラムはどのようにして独自のプロセスIDを取得できますか?


341

JavaプロセスのIDを取得するにはどうすればよいですか?

プラットフォームに依存したハックがいくつかあることは知っていますが、より一般的な解決策を望みます。



4
これは、JDK9で修正されることを意図しています。openjdk.java.net/jeps/102
Andrew

回答:


322

すべてのjvm実装での動作を保証できる、プラットフォームに依存しない方法はありません。 ManagementFactory.getRuntimeMXBean().getName()最高の(最も近い)ソリューションのように見えます。これは短く、おそらく広く使用されているすべての実装で機能します。

Linux + Windowsでは、12345@hostname12345プロセスIDである)のような値を返します。docsよると、この値については保証されないこと注意してください:

実行中のJava仮想マシンを表す名前を返します。返される名前文字列は任意の文字列にすることができ、Java仮想マシンの実装では、返される名前文字列にプラットフォーム固有の有用な情報を埋め込むことを選択できます。実行中の仮想マシンごとに異なる名前を付けることができます。

Java 9では、新しいプロセスAPIを使用できます。

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

2
このソリューションは本当に壊れやすいです。以下のHyperic Sigarに関する回答を参照してください。
Michael Klishin 14


111

JNAを使用できます。残念ながら、現在のプロセスIDを取得する共通のJNA APIはまだありませんが、各プラットフォームは非常に単純です。

ウィンドウズ

あなたがしていることを確認してくださいjna-platform.jar

int pid = Kernel32.INSTANCE.GetCurrentProcessId();

Unix

宣言:

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

次に:

int pid = CLibrary.INSTANCE.getpid();

Java 9

Java 9では、新しいプロセスAPIを使用して現在のプロセスIDを取得できます。最初に現在のプロセスのハンドルを取得し、次にPIDをクエリします。

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

4
+1しかし、セキュリティが制約された環境では動作しないはずです(tomcat、WebLogicなど)。
ATorras 2013

このgetpid()ソリューションはOS Xでも機能し、JNAが「システム」ライブラリを呼び出します。
ダニエルウィディス2016年

しかし、私error: cannot find symbolはjdk9 に乗ります
スカイツリー

56

これ、すべてのVMでは機能しない可能性がある、LinuxとWindowsの両方で機能するはずのバックドアメソッドです(元の例はこちら)。

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 2012

1
素晴らしい回避策。このメソッド(およびクラス内の他のメソッド)がパブリックではなく、簡単にアクセスできないのには十分な理由があると思います。それが何であるか知りたいです。
fragorl 2014

2
Oracle Javaチームは、Java以外のすべてのパッケージ(つまり、sun。*)を非表示にするつもりであると発表しました。上記と同様の実装がある場合は、コードが壊れないように別の方法を考えてください。
hfontanez 2014年

sun。*パッケージがおそらく削除されているか、アクセスできないため、私にとっては機能しません(VMManagementをタイプに解決できません)。
Mike Stoddart、2015年

リフレクションの仕組みにより、sun.management。*へのアクセスは必要ありません。getDeclaredMethodによって返されたオブジェクトに対してを実行するだけjvm.get(runtime)です。
Andrew T Finnell

36

Sigarを試してください。非常に広範なAPI。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();
}

6
このためにSIGARを使用する方法を説明すると、もっと多くの賛成票が得られます
Brad Mace

1
リンクが壊れています。あなたはこれの使い方の例を挙げていますが、Mavenの依存関係がありますか?
Jules

github.com/hyperic/sigarは使用可能な場所のようです。これは、Javaバインディングを備えたネイティブコードであることも示しています。これにより、多くのコンテキストでのソリューションとしての機能が低下する可能性があります。
Zastai 2018年

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()を確認してください。彼らはエキスパートなので、信頼できるクロスプラットフォームソリューションのように見えます。
エスピノサ2013

@Espinosa VisualVMは、OpenJDK / Oracle / GraalVM JVMでの実行のみをサポートします(2020現在)。つまり、それに応じて仮定を立てることができます。同じことをすると、ベンダー依存になり、たとえばJ9で実行するとコードが壊れる可能性があります。
するThorbjörnRavnアンデルセン

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());。なぜ余分な旋回が必要なのですか?
David Citron、2011

2
興味深いことに、@ Davidのコメントのトリックは実際に機能します。なぜ誰かが言うことができますか?getCanonicalFile()「自己」をPIDに変換するメソッドにある種の魔法?
GreenGiant

7
getCanonicalFile()はシンボリックリンク/ proc / self /-> / proc / 1234を解決します。ls-al / proc / selfを試してください
Michael

2
@DavidCitron +1!あなたは正しいです、私はgetCanonicalFileで考えていませんでした:-)
グランデス2013年

18

私のプロジェクト、GitHubのJavaSysMonをチェックしてください。プロセスIDとその他の要素(CPU使用量、メモリ使用量)のクロスプラットフォーム(現在はWindows、Mac OSX、Linux、Solaris)を提供します


Javaによって開始されたプロセスのPIDを取得することは可能ですか?または、この問題を修正するために「あなたの方法」でプロセスを開始しますか?
Panayotis 2016年

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で現在実行中のプロセスのプロセスインスタンスを取得する方法を説明できますか?
アウグスト

2016年にJava 9を使用するための素晴らしい回答です。javadocsへのリンクを追加できますか?ありがとう
crazyGuy

8

Scalaの場合:

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

解決。整数が必要な場合は、これを合計してワンライナーにすることができます。

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

誰かがすでにSpringブートを使用している場合、彼女/彼はorg.springframework.boot.ApplicationPidを使用する可能性があります

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

toString()メソッドは、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

私が見つけた最新のものは、少なくともLinuxで利用できるというシステムプロパティがあるsun.java.launcher.pidことです。私の計画はそれを使用することであり、それを使用することが見つからない場合JMX bean


Ubuntu 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ライブラリを直接使用してください。
エスピノサ2013

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.jarOracleのJDKではなくJREと一緒に配布するライブラリです!
  • tool.jarMavenリポジトリから取得することはできません。Mavenでそれを構成することは少しトリッキーです
  • tool.jarそれは簡単に配布可能ではありませんので、おそらくプラットフォーム依存(ネイティブ?)コードが含まれています
  • これは、すべての(ローカル)実行中のJVMアプリが「監視可能」であるという想定の下で実行されます。それはJava 6から、すべてのアプリが一般的にそうであるように見えます(あなたが積極的に反対に設定しない限り)
  • おそらくJava 6以降でのみ機能します
  • Eclipseはメインクラスを公開しないので、Eclipse PIDを簡単に取得できませんMonitoredVmUtilのバグ?

更新:JPSがこのように使用すること、つまりJvmstatライブラリ(tool.jarの一部)を再確認しました。したがって、JPSを外部プロセスとして呼び出す必要はありません。私の例が示すように、Jvmstatライブラリを直接呼び出します。この方法で、localhostで実行されているすべてのJVMのリストを取得することもできます。JPS ソースコードを参照してください:


mainClass.getName()が機能しない場合は、mainClass.getCanonicalName();を使用してみてください。
Narendra Parmar 2016

3

これを他のソリューションに追加します。

Java 10では、取得する process id

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

2

Apache 2.0ライセンスについてのAshwin Jayaprakashの回答(+1)に基づいてSIGAR、現在のプロセスのPIDのみを取得する方法を以下に示します。

import org.hyperic.sigar.Sigar;

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

すべてのプラットフォームで動作するわけではありませんが、ここに記載されているLinux、Windows、OS X、およびさまざまなUnixプラットフォームで動作します


1

あなたは試すことができますgetpid()JNR-のPosix

libcからgetpid()を呼び出すWindows POSIXラッパーがあります。



1

ちょっとした問題かもしれない解決策を見つけ、Windows 10以外のOSで試してみませんでしたが、注目に値すると思います。

あなた自身が作業して見つけた場合J2V8とnodejs、あなたはあなたのJavaプロセスのPIDを返す簡単なJavaScript関数を実行することができます。

次に例を示します。

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 2016年

-6

これは、同様の要件があったときに使用したものです。これにより、JavaプロセスのPIDが正しく決定されます。Javaコードで、事前定義されたポート番号でサーバーを生成し、OSコマンドを実行して、ポートで待機しているPIDを見つけます。Linuxの場合

netstat -tupln | grep portNumber

3
シェルスクリプトを呼び出す場合は、もっと簡単なことをするbash -c 'echo $PPID'か、/ proc が上記の答えを
Rich
弊社のサイトを使用することにより、あなたは弊社のクッキーポリシーおよびプライバシーポリシーを読み、理解したものとみなされます。
Licensed under cc by-sa 3.0 with attribution required.