В работающей JVM, как программно определить параметры jvm, используемые при запуске?

Предыстория: я выполняю некоторые тесты производительности в приложении Java, которое запускается через несколько уровней косвенности, поэтому я не совсем уверен, что приложение запускается с флагами, которые я думаю. Я хотел бы, чтобы мое приложение включало проверку работоспособности (до того, как оно начнет тест производительности) и включало в результаты (после теста) информацию о том, как была настроена JVM, например:

  • Какой сборщик мусора использовался?
  • Он активно выполнял профилирование процессора?
  • Был ли он регистрирует активность gc?
  • Был ли он в режиме -Xint или -Xmixed?
  • Был ли установлен -XX:ParallelGCThreads -- если да, то какой, а если нет, то какой по умолчанию для этой сборки?
  • Был/есть ли -XX:UseCompressedOops включенным или выключенным?
  • и т.п.

Есть ли способ для Java-кода (внутри работающей JVM) запрашивать фактические параметры, используемые для его содержащей JVM? (Предположим, что я не вижу командную строку, которая запустила меня, поэтому я не могу повторно проанализировать эти флаги.)

Если нет универсального способа определить это, также приветствуются ответы, относящиеся к конкретной реализации JVM.

ОБНОВИТЬ:

Важно, чтобы решение могло знать, каковы значения по умолчанию для любого значения, которое не указано явно в командной строке. В противном случае потребуется много (подверженной ошибкам) ​​работы, чтобы найти значение по умолчанию для данной комбинации JVM/платформа/версия/архитектура. Я тестирую самые разные JVM, поэтому мне не нужно вручную выяснять, какие настройки по умолчанию установлены для каждого параметра в каждом выпуске jvm.


person Mickalot    schedule 07.06.2013    source источник
comment
Вы можете перечислить процесс JVM, запущенный PID, с помощью ps -ef, и там вы можете увидеть все входные аргументы этого процесса. Это должно работать для любого типа JVM.   -  person Aleš    schedule 08.06.2013
comment
@АлесДж. ОП заявил, что подход командной строки не вариант   -  person Oleg Mikheev    schedule 08.06.2013
comment
@АлесДж. - это дало бы мне только явно заданные значения, поэтому я не получил бы никакой информации о неявных значениях по умолчанию JVM (см. Обновление редактирования вопроса). :-(   -  person Mickalot    schedule 08.06.2013
comment
Я вижу, очень плохо, это сработало бы. Я думаю, что не существует независимого от вендора решения, для каждой ВМ нужен будет свой подход. Значения по умолчанию для неуказанных аргументов обычно легко найти в документации.   -  person Aleš    schedule 08.06.2013


Ответы (3)


Вы можете использовать клиент JMX (например, VisualVM), а затем вызвать getVMOption(String name), см. HotSpotDiagnosticMXBean.

Или, если вы можете передать хотя бы один набор флагов, чтобы включить ведение журнала JVM, это должен быть --XX:+LogVMOutput -XX:LogFile=jvm.log, а затем проанализировать вывод журнала из вашего приложения. Журнал содержит все флаги/параметры, используемые для запуска JVM.

Другой вариант — перечислить процесс JVM, запущенный PID, с помощью ps -ef, и там вы можете увидеть все входные аргументы этого процесса. Это должно работать для любого типа JVM.

person Aleš    schedule 08.06.2013
comment
не является ли HotSpotDiagnosticMXBean Oracle JVM специфичным? - person Oleg Mikheev; 08.06.2013
comment
@OlegMikheev - Хотя это не идеально, я бы согласился на любые решения, специфичные для JVM (большинство пользователей, вероятно, будут использовать JVM Hotspot). Но HotSpotDiagnosticMXBean в любом случае выглядит как неправильный bean-компонент... он сообщает мне, какая диагностика используется (например, что он должен регистрировать при выполнении GC), а не как настроена виртуальная машина. - person Mickalot; 08.06.2013
comment
@АлесДж. -- Я попробовал несколько JDK Sun/Oracle J2SE (в основном 1.6/1.7 32/64-бит в Linux), и ни один из них, похоже, не распознал -XX:+LogVMOutput. Я также не вижу его здесь: oracle.com /technetwork/java/javase/tech/ . Какую JVM вы используете, которая принимает это? - person Mickalot; 08.06.2013
comment
Это все зависит от Hotspot. Попробуйте -XX:+UnlockDiagnosticVMOptions, он должен работать с Hotspot 6 и 7. - person Aleš; 08.06.2013
comment
Я выбираю это как принятый ответ, потому что не вижу способа принять @AlesJ. прокомментируйте вопрос, что нет независимого от вендора решения, для каждой ВМ нужен свой подход. К сожалению, ответ на вопрос «Как мне…» — «Вы этого не сделаете». - person Mickalot; 23.08.2013

Вы можете получить аргументы командной строки с помощью

ManagementFactory.getRuntimeMXBean().getInputArguments();
person ZhongYu    schedule 08.06.2013
comment
Это была моя первая мысль, но можно ли ее использовать для определения таких особенностей, как какой сборщик мусора использовался, активно ли он профилирует процессор и так далее? Я считаю, что вы должны уточнить в своем ответе. - person FThompson; 08.06.2013
comment
Я полностью ценю это (и это было первое, что я попробовал), но причина, по которой это не то, что я ищу, заключается в том, что если параметр JVM не указан, он установлен на любое значение по умолчанию JVM, и это отсутствует в этом списке (который содержит только явно указанные аргументы). Таким образом, это не отвечает на вопрос, что используется по умолчанию для этой сборки? Я тестирую на множестве разных машин, каждая из которых может иметь немного отличающуюся сборку с немного разными настройками по умолчанию. - person Mickalot; 08.06.2013

В следующем коде Java 7 будут перечислены все параметры JVM, возвращаемые -XX:+PrintFlagsFinal. Он пытается использовать отражение для доступа к защищенному пакетом файлу Flag вспомогательный класс (доступен, начиная с Java 6), и возвращается к HotSpotDiagnosticMXBean.getDiagnosticOptions(), если это не сработает.

// load the diagnostic bean first to avoid UnsatisfiedLinkError
final HotSpotDiagnosticMXBean hsdiag = ManagementFactory
        .getPlatformMXBean(HotSpotDiagnosticMXBean.class);
List<VMOption> options;
try {
    final Class<?> flagClass = Class.forName("sun.management.Flag");
    final Method getAllFlagsMethod = flagClass.getDeclaredMethod("getAllFlags");
    final Method getVMOptionMethod = flagClass.getDeclaredMethod("getVMOption");
    getAllFlagsMethod.setAccessible(true);
    getVMOptionMethod.setAccessible(true);
    final Object result = getAllFlagsMethod.invoke(null);
    final List<?> flags = (List<?>) result;
    options = new ArrayList<VMOption>(flags.size());
    for (final Object flag : flags) {
        options.add((VMOption) getVMOptionMethod.invoke(flag));
    }
} catch (ClassNotFoundException | NoSuchMethodException | IllegalAccessException
        | InvocationTargetException | ClassCastException e) {
    if (hsdiag != null) {
        // only includes writable external flags
        options = hsdiag.getDiagnosticOptions();
    } else {
        options = Collections.emptyList();
    }
}
final Map<String, VMOption> optionMap = new TreeMap<>();
for (final VMOption option : options) {
    optionMap.put(option.getName(), option);
}
for (final VMOption option : optionMap.values()) {
    System.out.println(option.getName() + " = " + option.getValue() + " (" +
            option.getOrigin() + ", " +
            (option.isWriteable() ? "read-write" : "read-only") + ")");
}
System.out.println(options.size() + " options found");

С 7u71 у меня получается 663 варианта, или с -XX:+UnlockDiagnosticVMOptions -XX:+UnlockExperimentalVMOptions 779.

person Trevor Robinson    schedule 24.03.2015