Как программа Java может получить свой собственный идентификатор процесса?

StackOverflow https://stackoverflow.com/questions/35842

  •  09-06-2019
  •  | 
  •  

Вопрос

Как мне получить идентификатор моего Java-процесса?

Я знаю, что есть несколько зависящих от платформы взломов, но я бы предпочел более общее решение.

Это было полезно?

Решение

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

В linux + windows возвращает значение вроде 12345@hostname (12345 - идентификатор процесса). Остерегайтесь, что в соответствии с документы , нет никаких гарантий относительно этого значения:

  

Возвращает имя, представляющее работающую виртуальную машину Java.   возвращаемая строка имени может быть любой произвольной строкой и виртуальной Java   реализация машины может выбрать для вставки полезной для конкретной платформы   информация в возвращаемой строке имени. Каждая работающая виртуальная машина   может иметь другое имя.

В Java 9 новый API процесса можно использовать:

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

Другие советы

Вы могли бы использовать ЮНА.К сожалению, пока не существует общего JNA API для получения текущего идентификатора процесса, но каждая платформа довольно проста:

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

Вот метод бэкдора, который может работать не со всеми виртуальными машинами, но должен работать как на 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);

Попробуйте 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();
    }

Следующий метод пытается извлечь 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>").

Для более старой 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";
}

Вы можете проверить мой проект: JavaSysMon на GitHub. Он предоставляет идентификатор процесса и кучу других вещей (использование процессора, использование памяти) кроссплатформенных (в настоящее время Windows, Mac OSX, Linux и Solaris)

Начиная с Java 9 существует метод Process.getPid (), который возвращает собственный идентификатор процесса:

public abstract class Process {

    ...

    public long getPid();
}

Чтобы получить идентификатор текущего процесса Java, можно использовать интерфейс ProcessHandle:

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

В Scala:

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

Это должно дать вам обходной путь в системах Unix до выпуска Java 9. (Я знаю, что вопрос был о Java, но, поскольку у Scala нет аналогичного вопроса, я хотел оставить это для пользователей Scala, которые могут столкнуться с тем же вопросом.)

Для полноты картины в Пружинный Ботинок для

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

решение.Если требуется целое число, то его можно суммировать до однострочного:

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

Если кто-то уже использует Spring boot, он / она может использовать org.springframework.boot.Идентификатор приложения

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

Метод toString() выводит pid или '???'.

Предостережения при использовании ManagementFactory уже обсуждаются в других ответах.

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

Последнее, что я обнаружил, это то, что есть системное свойство с именем sun.java.launcher.pid, которое доступно по крайней мере в Linux. Мой план состоит в том, чтобы использовать это, и если не найдено, использовать JMX bean.

java.lang.management.ManagementFactory.getRuntimeMXBean().getName().split("@")[0]

Это зависит от того, откуда вы ищете информацию.

Если вы ищете информацию из консоли, вы можете использовать команду 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) о 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, перечисленные здесь .

Это код, который использует 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;настроить его с помощью Maven немного сложнее
  • Тот Самый tool.jar вероятно, содержится зависит от платформы (родной?) код, поэтому он не легко распределяемая
  • Он выполняется в предположении, что все (локальные) запущенные приложения JVM "поддаются мониторингу".Похоже, что с Java 6 все приложения, как правило, (если вы не настроите противоположное)
  • Вероятно, это работает только для Java 6 +
  • Eclipse не публикует основной класс, поэтому вы не сможете легко получить Eclipse PID Ошибка в MonitoredVmUtil?

Обновить:Я только что дважды проверил, что JPS использует этот способ, то есть библиотеку Jvmstat (часть tool.jar).Таким образом, нет необходимости вызывать JPS как внешний процесс, вызывайте библиотеку Jvmstat напрямую, как показывает мой пример.Таким образом, вы также можете получить список всех JVM, запущенных на localhost.Смотрите JPS исходный код:

Вы можете попробовать getpid() в JNR-Posix .

У него есть оболочка Windows POSIX, которая вызывает getpid () из libc.

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

Я нашел решение, которое может показаться немного странным, и я не пробовал его на других ОС, кроме Windows 10, но, думаю, это стоит заметить.

Если вы обнаружите, что работаете с J2V8 и nodejs, вы можете запустить простую функцию JavaScript, возвращающую вам PID процесса Java.

Вот пример:

public static void main(String[] args) {
    NodeJS nodeJS = NodeJS.createNodeJS();
    int pid = nodeJS.getRuntime().executeIntegerScript("process.pid;\n");
    System.out.println(pid);
    nodeJS.release();
}

Добавление к другим решениям.

с Java 10, чтобы получить process id

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

Вот мое решение:

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

netstat -tupln | grep portNumber
Лицензировано под: CC-BY-SA с атрибуция
Не связан с StackOverflow
scroll top