10

背景:我正在对通过多层间接启动的 Java 应用程序进行一些性能测试,因此我不能完全确定应用程序是否使用我认为的标志启动。我希望我的应用程序包括一个健全性检查(在它开始其性能测试之前)并在结果中(测试之后)包括有关如何调整 JVM 的信息,例如:

  • 使用了哪个垃圾收集器?
  • 是否/正在积极进行 cpu 分析?
  • 是否/正在记录 gc 活动?
  • 是/现在-Xint还是-Xmixed模式?
  • 是否/已-XX:ParallelGCThreads设置——如果是,设置为什么,如果不是,此构建的默认设置是什么?
  • 是否-XX:UseCompressedOops开启或关闭?
  • 等等

Java 代码有没有办法(在运行的 JVM 中)查询用于其包含的 JVM 的实际选项?(假设我看不到启动我的命令行,所以我无法重新解析这些标志。)

如果没有通用的方法来确定这一点,也欢迎特定于特定 JVM 实现的答案。

更新:

对于解决方案来说,能够知道命令行上未明确提供的任何值的默认值是什么很重要。否则,查找给定组合 JVM/平台/版本/架构的默认值将涉及大量(容易出错的)工作。我正在对各种 JVM 进行测试,因此我不想手动找出每个 jvm 版本中每个参数的默认设置。

4

3 回答 3

6

您可以通过以下方式获取命令行参数

ManagementFactory.getRuntimeMXBean().getInputArguments();
于 2013-06-08T00:07:32.417 回答
4

以下 Java 7 代码将列出-XX:+PrintFlagsFinal. 它尝试使用反射来访问受包保护的帮助程序类(自 Java 6 起可用),如果不起作用则Flag回退。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。

于 2015-03-24T02:23:43.147 回答
2

您可以使用 JMX 客户端(如 VisualVM)然后调用getVMOption(String name),请参阅HotSpotDiagnosticMXBean

或者,如果您可以传递至少一组标志来启用 JVM 日志记录,那么它应该是--XX:+LogVMOutput -XX:LogFile=jvm.log然后解析来自您的应用程序的日志输出。该日志包含用于启动 JVM 的所有标志/参数。

另一种选择是列出由 PID 启动的 JVM 进程ps -ef,在那里您可以看到该进程的所有输入参数。这应该适用于任何 JVM 类型。

于 2013-06-08T00:21:41.053 回答