是否可以在运行时禁用 `-XX:+PrintCompilation` 和 `-verbose:gc"`?

mer*_*011 8 java performance jvm jvm-hotspot performance-testing

如此答案中所建议的,我在运行性能测试时使用以下标志。

  -XX:+PrintCompilation
  -verbose:gc
Run Code Online (Sandbox Code Playgroud)

这对于调试计时阶段发生的 JVM 活动非常有用,但是当我只是计算统计信息并打印有关刚刚运行的基准测试的输出时,输出就没那么有用了。

有没有办法在运行时禁用这些标志中的一个或两个,以便我可以在计时阶段后关闭它们?

apa*_*gin 9

在运行时关闭 GC 日志很容易,因为 GC 日志包含在Unified JVM Logging框架中。

从命令行

jcmd <pid> VM.log what=gc=off
Run Code Online (Sandbox Code Playgroud)

从应用程序中

ManagementFactory.getPlatformMBeanServer().invoke(
        new ObjectName("com.sun.management:type=DiagnosticCommand"),
        "vmLog",
        new Object[]{new String[]{"what=gc=off"}},
        new String[]{"[Ljava.lang.String;"}
);
Run Code Online (Sandbox Code Playgroud)

不幸的是,-XX:+PrintCompilation它不是一个可管理的标志,也不遵守统一 JVM 日志记录。但是,也可以更改它。

我已经在这个答案中展示了如何使用 Serviceability Agent 从外部修改 JVM 标志。这是执行此操作的另一种方法。

这个想法是找到标志的内存地址并修改内存中的值。下面是如何在 Linux 上实现这一点的示例。

  1. 找到加载的JVM库的基地址:
$ grep libjvm.so /proc/<pid>/maps
7f57435ca000-7f574470d000 r-xp 00000000 fd:00 2342674    /usr/java/jdk-11/lib/server/libjvm.so
^^^^^^^^^^^^
Run Code Online (Sandbox Code Playgroud)
  1. PrintCompilation符号在 中的偏移量libjvm.so
$ nm /usr/java/jdk-11/lib/server/libjvm.so | grep PrintCompilation
000000000144d7ff b PrintCompilation
^^^^^^^^^^^^^^^^
Run Code Online (Sandbox Code Playgroud)
  1. 现在0在地址处写入进程内存base + offset
$ printf '\x00' | dd of=/proc/<pid>/mem bs=1 count=1 seek=$((0x7f57435ca000 + 0x144d7ff)) conv=notrunc
Run Code Online (Sandbox Code Playgroud)

就是这样。PrintCompilation标志已关闭。

奖金

同样的技巧可以直接从 Java 应用程序中完成:/proc/pid/maps像普通文件一样读取,解析 ELF 格式libjvm.so以找到符号偏移量,最后使用Unsafe在给定地址写入一个字节。这是完整的示例

更新

我添加了一个macOS 示例,用于在 Java 应用程序中在运行时修改 JVM 标志。用法很简单

VMFlags.setBooleanFlag("PrintCompilation", true);
Run Code Online (Sandbox Code Playgroud)

  • @akuzminykh 由于历史原因。我相信该标志*可以*在运行时是可管理的,只是以前没有人关心。以这种方式更改标志是安全的,因为它只是像常规 bool 变量一样被查询,并且除了日志记录之外,对此标志没有隐式依赖。 (2认同)