正如这个答案所建议的那样,在运行性能测试时,我使用了以下标志。
-XX:+PrintCompilation
-verbose:gc
在定时阶段调试JVM活动非常有用,但是当我仅计算统计信息并打印有关刚运行的基准测试的输出时,输出就不太有用了。
是否有一种方法可以在运行时禁用其中一个或两个标志,以便我可以在计时阶段之后关闭它们?
正如这个答案所建议的那样,在运行性能测试时,我使用了以下标志。
-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日志记录。但是,也有可能对其进行更改。$ grep libjvm.so /proc/<pid>/maps
7f57435ca000-7f574470d000 r-xp 00000000 fd:00 2342674 /usr/java/jdk-11/lib/server/libjvm.so
^^^^^^^^^^^^
libjvm.so
中PrintCompilation
符号的偏移量:$ nm /usr/java/jdk-11/lib/server/libjvm.so | grep PrintCompilation
000000000144d7ff b PrintCompilation
^^^^^^^^^^^^^^^^
base + offset
的进程内存中写入0
:$ 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
在给定地址写入一个字节。这是完整的示例。
更新
我添加了MacOS示例,演示了如何从Java应用程序内部运行时修改JVM标志。使用方法非常简单:
VMFlags.setBooleanFlag("PrintCompilation", true);
-XX:+PrintCompilation
时,原因是什么?这样更改是否可能存在安全风险? - akuzminykh