Як програма Java може отримати свій ідентифікатор процесу?


341

Як отримати ідентифікатор мого процесу Java?

Я знаю, що існує кілька хакерських залежностей від платформи, але я вважаю за краще більш загальне рішення.


1
Посилання на питання щодо Linux: Як знайти свій PID на Java або JRuby в Linux?
Jarekczek

4
Це має бути зафіксовано в JDK9. openjdk.java.net/jeps/102
Андрій

Відповіді:


322

Не існує незалежного від платформи способу, який би гарантував роботу у всіх реалізаціях jvm. ManagementFactory.getRuntimeMXBean().getName()виглядає як найкраще (найближче) рішення. Це коротко і, ймовірно, працює в кожній реалізації в широкому використанні.

У Linux + Windows він повертає значення типу 12345@hostname( 12345ідентифікатор процесу). Але будьте обережні, згідно з документами , гарантій щодо цього значення немає:

Повертає ім'я, що представляє працюючу віртуальну машину Java. Повернута рядок імені може бути будь-якою довільною рядком, і реалізація віртуальної машини Java може вибрати вбудовувану корисну інформацію, що відповідає платформі, у рядок імені, що повертається. Кожна запущена віртуальна машина може мати іншу назву.

У Java 9 можна використовувати новий API процесу :

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

2
Це рішення справді крихке. Дивіться відповідь про Hyperic Sigar нижче.
Майкл Клішин

цей pid добре писати у файл блокування як stackoverflow.com/a/9020391/1422630
Водолій Power

111

Ви могли використовувати JNA . На жаль, ще немає загального API JNA, щоб отримати поточний ідентифікатор процесу, але кожна платформа досить проста:

Windows

Переконайтеся, що у вас є 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 процесу може бути використаний для отримання поточного ідентифікатора процесу. Спочатку ви захопите ручку до поточного процесу, а потім запитаєте PID:

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

4
+1 Але я боюся, що в умовах обмеженої безпеки він не повинен працювати (tomcat, WebLogic тощо).
Аторрас

getpid()Рішення також працює на OS X, за допомогою виклику ЮНА в бібліотеку «System».
Даніель Віддіс

Однак я отримую error: cannot find symbolза jdk9
skytree

56

Ось метод "бекдор", який може працювати не з усіма віртуальними машинами, але повинен працювати як на 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.
Друпад Панчал

1
Гарний спосіб подолання. Я припускаю, що є вагома причина, чому цей метод (та інші в класі) не є загальнодоступними та легкодоступними, і мені цікаво знати, що це таке.
fragorl

2
Команда Oracle Java оголосила, що має намір приховати всі не-java-пакети (тобто sun. *). Я вважаю, що починаючи з Java 10 (заплановано на 2018 рік - можливо, Java 9). Якщо у вас є аналогічна реалізація, як у вищеописаній, ви можете розглянути альтернативу, щоб ваш код не зламався.
hfontanez

Не працює для мене, як сонце. * Пакунки, ймовірно, видалені або недоступні (VMManagement не може бути розв'язаний до типу).
Майк Стоддарт

Завдяки тому, як працює роздум, доступ до sun.management. * Не потрібен. Просто виконайте getDeclaredMethodна об’єкті, поверненому користувачем jvm.get(runtime).
Ендрю Т Фіннелл

36

Спробуйте Сігар . дуже широкі 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 для цього
Бред Мейс

1
Посилання розірвано. Ви наводите приклад, як це використовувати, але чи існує залежність від нього?
Жуль

github.com/hyperic/sigar, здається, є зручним місцем; це також показує, що це власний код з прив’язками Java, що може зробити його менш вирішенням для багатьох контекстів.
Застаї

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 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());. Чому зайві гірації?
Девід Цитрон

2
Для цікавих, фокус у коментарі @David насправді працює. Хтось може сказати, чому? Якась магія в getCanonicalFile()методі, який перетворює "Я" на PID?
GreenGiant

7
getCanonicalFile () вирішує symlink / proc / self / -> / proc / 1234, спробуйте ls -al / proc / self
Michael

2
@DavidCitron +1! ви праві, я не думав у getCanonicalFile :-)
ggrandes

18

Ви можете перевірити мій проект: JavaSysMon на GitHub. Він надає ідентифікатор процесу та безліч інших матеріалів (використання процесора, використання пам'яті) на всій платформі (зараз Windows, Mac OSX, Linux та Solaris)


Чи можливо отримати PID процесу, запущеного Java? Або запустити процес "по-своєму", щоб виправити цю проблему?
Панайотис

17

Оскільки у Java 9 існує метод Process.getPid (), який повертає початковий ідентифікатор процесу:

public abstract class Process {

    ...

    public long getPid();
}

Для отримання ідентифікатора процесу поточного Java процесу можна використовувати ProcessHandleінтерфейс:

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

2
Чи можете ви пояснити, як отримати екземпляр Process для поточного запущеного процесу в Java 9?
Августо

Чудова відповідь на використання Java 9 у 2016 році! Чи можете ви додати посилання на javadocs? дякую
crazyGuy

8

У Scala:

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

Це має забезпечити вирішення проблем у системах Unix до виходу Java 9. (Я знаю, питання стосувалося 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 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яка доступна принаймні на Linux. Мій план полягає в тому, щоб використовувати це, і якщо його не знайти, використовувати JMX bean.


У моєму випадку з Ubuntu 16.04 та Java 8, він повертається до нуля
david.perez

4

Це залежить від того, звідки ви шукаєте інформацію.

Якщо ви шукаєте інформацію з консолі, ви можете скористатися командою jps. Команда дає вихід, схожий на команду Unix ps і поставляється з JDK, оскільки я вважаю, що 1.5

Якщо ви дивитесь на процес, RuntimeMXBean (як сказав Wouter Coekaerts) - це, мабуть, найкращий вибір. Вихід з getName () для Windows за допомогою Sun JDK 1.6 u7 має форму [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бібліотека, що поширюється за допомогою Oracle JDK, але не JRE!
  • Ви не можете дістатися tool.jarз Maven repo; налаштувати його за допомогою Maven - трохи хитро
  • tool.jar, Ймовірно , містить залежний (рідна?) Код платформи , так що не легко розповсюджуваний
  • Він працює за припущенням, що всі (локальні) запущені програми JVM є "контрольованими". Схоже, що з Java 6 зазвичай усі програми (якщо ви не налаштовуєте навпаки)
  • Можливо, це працює лише для Java 6+
  • Eclipse не публікує основний клас, тож ви не отримаєте Eclipse PID легко помилка в MonitoredVmUtil?

ОНОВЛЕННЯ: Я лише двічі перевірив, що JPS використовує цей спосіб, тобто бібліотеку Jvmstat (частина інструменту.jar). Тому не потрібно викликати JPS як зовнішній процес, зателефонуйте безпосередньо до бібліотеки Jvmstat, як показує мій приклад. Ви також можете отримати список усіх спільних бігу JVM на localhost таким чином. Див. Вихідний код JPS :


якщо mainClass.getName () не працює, спробуйте використовувати mainClass.getCanonicalName ();
Нарендра Пармар

3

Я додаю це до інших рішень.

з Java 10, щоб отримати process id

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

2

На підставі Ashwin Jayaprakash в відповіді (+1) про Apache 2.0 ліцензованих 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 .

Він має оболонку для Windows POSIX, яка викликує getpid () off libc.


1

Я знаю, що це стара тема, але я хотів зауважити, що API для отримання PID (а також інші маніпуляції з процесом Java під час виконання) додається до класу Process в JDK 9: http: // openjdk. java.net/jeps/102


9
Нічого собі, це було швидко. Пройшло всього близько семи років! 😃
Дмитро Шехтман

1

Я знайшов рішення, яке може бути трохи кращим випадком, і я не пробував його в іншій ОС, ніж Windows 10, але я думаю, що це варто помітити.

Якщо ви виявите, що ви працюєте з J2V8 і nodejs, ви можете запустити просту функцію 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

-6

Це те, що я використовував, коли у мене були подібні вимоги. Це правильно визначає PID процесу Java. Нехай ваш код Java породжує сервер на заздалегідь визначений номер порту, а потім виконайте команди ОС, щоб дізнатись прослуховування PID на порту. Для Linux

netstat -tupln | grep portNumber

3
Якщо ви викликаєте сценарії оболонки, ви можете також зробити щось простіше, як- bash -c 'echo $PPID'от / відповіді
Rich
Використовуючи наш веб-сайт, ви визнаєте, що прочитали та зрозуміли наші Політику щодо файлів cookie та Політику конфіденційності.
Licensed under cc by-sa 3.0 with attribution required.