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

8

正如这个答案所建议的那样,在运行性能测试时,我使用了以下标志。

  -XX:+PrintCompilation
  -verbose:gc

在定时阶段调试JVM活动非常有用,但是当我仅计算统计信息并打印有关刚运行的基准测试的输出时,输出就不太有用了。

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


是的,这是可能的。您感兴趣的操作系统和JDK版本是什么? - apangin
@apangin 我在 Linux 和 OSX 上运行,使用 JDK 11。 - merlin2011
1个回答

9

在运行时关闭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
^^^^^^^^^^^^^^^^

现在,在地址为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);

谢谢!在OSX中有类似的技巧吗? - merlin2011
我想知道,当直接无法管理 -XX:+PrintCompilation 时,原因是什么?这样更改是否可能存在安全风险? - akuzminykh
@merlin2011 是的。您想从外部更改标志还是从Java代码中更改? - apangin
2
出于历史原因,我相信标志可以在运行时进行管理,只是以前没有人关心过。这种方式更改标志是安全的,因为它只是像常规布尔变量一样被查询,并且除了用于日志记录之外,没有隐含的依赖关系。@akuzminykh - apangin

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接