java - 是否可以在运行时禁用 `-XX:+PrintCompilation` 和 `-verbose:gc"`?
问题描述
正如这个答案中所建议的,我在运行性能测试时使用了以下标志。
-XX:+PrintCompilation
-verbose:gc
这对于调试在计时阶段发生的 JVM 活动非常有用,但是当我只是计算统计数据并打印有关刚刚运行的基准的输出时,输出就不那么有用了。
有没有办法在运行时禁用这些标志中的一个或两个,以便我可以在计时阶段之后将它们关闭?
解决方案
在运行时关闭 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 标志。这是另一种方法。
这个想法是找到标志的内存地址并修改内存中的值。以下是如何在 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
像普通文件一样读取,解析 ELF 格式libjvm.so
以找到符号偏移量,最后使用Unsafe
在给定地址写入一个字节。这是完整的例子。
更新
我添加了一个macOS 示例,该示例在运行时从 Java 应用程序中修改 JVM 标志。用法很简单
VMFlags.setBooleanFlag("PrintCompilation", true);
推荐阅读
- java - 使用 Java Spring JPA 为 liquibase 中的表名添加前缀
- python - Python字符串按特定字符拆分
- php - Php,依赖注入,如何替换对象(用于测试)?
- asp.net-core - 无法使用 HttpContext 访问用户
- python - python - 在python上的Tkinter上使用Entry时如何禁用键盘输入?
- angular - 在 Angular 中处理两种类型的用户身份验证
- javascript - FaunaDB FQL - 找不到表单/函数,或无效的参数键:{ params }
- r - 使用循环子集日期集 - 将文件拆分为更小的多个数据集
- reactjs - 材质ui中是否有带有“showmore”的折叠组件
- javascript - Javascript - 从 innerHTML 元素获取 Id