是否可以在运行时禁用"-XX:+打印编译"和"-verbose:gc"?



根据这个答案的建议,我在运行性能测试时使用以下标志。

-XX:+PrintCompilation
-verbose:gc

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

是否有一种方法可以在运行时禁用一个或两个标志,以便我可以在计时阶段后关闭它们?

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

从命令行

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日志记录。但是,也可以更改它。

我已经在这个回答中展示了如何使用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
^^^^^^^^^^^^
  1. 查找libjvm.soPrintCompilation符号的偏移量:
$ nm /usr/java/jdk-11/lib/server/libjvm.so | grep PrintCompilation
000000000144d7ff b PrintCompilation
^^^^^^^^^^^^^^^^
  1. 现在将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在给定地址上写入一个字节。下面是完整的示例。

我添加了一个在运行时从Java应用程序中修改JVM标志的macOS示例。用法就像

一样简单
VMFlags.setBooleanFlag("PrintCompilation", true);

最新更新