是否可以在运行时禁用 `-XX:+PrintCompilation` 和 `-verbose:gc"`?
Is it possible to disable `-XX:+PrintCompilation` and `-verbose:gc"` at runtime?
正如 this answer 中所建议的那样,我在 运行 性能测试时使用了以下标志。
-XX:+PrintCompilation
-verbose:gc
这对于调试在计时阶段发生的 JVM 活动非常有用,但是当我只是计算统计数据和打印有关 运行.[=12 的基准的输出时,输出就不太有用了=]
有没有办法在运行时禁用这些标志中的一个或两个,以便我可以在计时阶段后将它们关闭?
在运行时关闭 GC 日志很容易,因为 GC 日志包含在 Unified JVM Logging 框架中。
从命令行
jcmd <pid> VM.log what=gc=off
从应用程序内部
ManagementFactory.getPlatformMBeanServer().invoke(
new ObjectName("com.sun.management:type=DiagnosticCommand"),
"vmLog",
new Object[]{new String[]{"what=gc=off"}},
new String[]{"[Ljava.lang.String;"}
);
不幸的是,-XX:+PrintCompilation
不是一个可管理的标志并且不遵守统一的 JVM 日志记录。但是,也可以更改它。
我已经在 中展示了如何使用可服务性代理在外部修改 JVM 标志。这是执行此操作的另一种方法。
思路是找到flag所在的内存地址,修改内存中的正确值。以下是如何在 Linux.
上实现此目的的示例
- 找到加载的JVM库的基址:
$ grep libjvm.so /proc/<pid>/maps
7f57435ca000-7f574470d000 r-xp 00000000 fd:00 2342674 /usr/java/jdk-11/lib/server/libjvm.so
^^^^^^^^^^^^
- 求
PrintCompilation
符号在libjvm.so
中的偏移量:
$ nm /usr/java/jdk-11/lib/server/libjvm.so | grep PrintCompilation
000000000144d7ff b PrintCompilation
^^^^^^^^^^^^^^^^
- 现在将
0
写入进程内存地址base + offset
:
$ printf '\x00' | dd of=/proc/<pid>/mem bs=1 count=1 seek=$((0x7f57435ca000 + 0x144d7ff)) conv=notrunc
就是这样。 PrintCompilation
标志已关闭。
奖金
可以直接从 Java 应用程序完成相同的技巧:像读取普通文件一样读取 /proc/pid/maps
,解析 libjvm.so
的 ELF 格式以找到符号偏移量,最后使用Unsafe
在给定地址写入一个字节。 Here is the complete example.
更新
我在 Java 应用程序中添加了在运行时修改 JVM 标志的 macOS example。用法很简单
VMFlags.setBooleanFlag("PrintCompilation", true);
正如 this answer 中所建议的那样,我在 运行 性能测试时使用了以下标志。
-XX:+PrintCompilation
-verbose:gc
这对于调试在计时阶段发生的 JVM 活动非常有用,但是当我只是计算统计数据和打印有关 运行.[=12 的基准的输出时,输出就不太有用了=]
有没有办法在运行时禁用这些标志中的一个或两个,以便我可以在计时阶段后将它们关闭?
在运行时关闭 GC 日志很容易,因为 GC 日志包含在 Unified JVM Logging 框架中。
从命令行
jcmd <pid> VM.log what=gc=off
从应用程序内部
ManagementFactory.getPlatformMBeanServer().invoke(
new ObjectName("com.sun.management:type=DiagnosticCommand"),
"vmLog",
new Object[]{new String[]{"what=gc=off"}},
new String[]{"[Ljava.lang.String;"}
);
不幸的是,-XX:+PrintCompilation
不是一个可管理的标志并且不遵守统一的 JVM 日志记录。但是,也可以更改它。
我已经在
思路是找到flag所在的内存地址,修改内存中的正确值。以下是如何在 Linux.
上实现此目的的示例- 找到加载的JVM库的基址:
$ grep libjvm.so /proc/<pid>/maps
7f57435ca000-7f574470d000 r-xp 00000000 fd:00 2342674 /usr/java/jdk-11/lib/server/libjvm.so
^^^^^^^^^^^^
- 求
PrintCompilation
符号在libjvm.so
中的偏移量:
$ nm /usr/java/jdk-11/lib/server/libjvm.so | grep PrintCompilation
000000000144d7ff b PrintCompilation
^^^^^^^^^^^^^^^^
- 现在将
0
写入进程内存地址base + offset
:
$ printf '\x00' | dd of=/proc/<pid>/mem bs=1 count=1 seek=$((0x7f57435ca000 + 0x144d7ff)) conv=notrunc
就是这样。 PrintCompilation
标志已关闭。
奖金
可以直接从 Java 应用程序完成相同的技巧:像读取普通文件一样读取 /proc/pid/maps
,解析 libjvm.so
的 ELF 格式以找到符号偏移量,最后使用Unsafe
在给定地址写入一个字节。 Here is the complete example.
更新
我在 Java 应用程序中添加了在运行时修改 JVM 标志的 macOS example。用法很简单
VMFlags.setBooleanFlag("PrintCompilation", true);